]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/plugins/rp-pppoe/discovery.c
rp-pppoe: allow MTU to be increased up to 1500
[ppp.git] / pppd / plugins / rp-pppoe / discovery.c
index 6e25ae7361e9167b7f1ab01f58b4ba8e6d1d584c..a856490f96fb7ba887ae2e8dda16a91eae358769 100644 (file)
@@ -14,6 +14,8 @@ static char const RCSID[] =
 #define _GNU_SOURCE 1
 #include "pppoe.h"
 #include "pppd/pppd.h"
+#include "pppd/fsm.h"
+#include "pppd/lcp.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -110,6 +112,7 @@ parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
 {
     struct PacketCriteria *pc = (struct PacketCriteria *) extra;
     PPPoEConnection *conn = pc->conn;
+    UINT16_t mru;
     int i;
 
     switch(type) {
@@ -140,6 +143,19 @@ parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
        conn->relayId.length = htons(len);
        memcpy(conn->relayId.payload, data, len);
        break;
+    case TAG_PPP_MAX_PAYLOAD:
+       if (len == sizeof(mru)) {
+           memcpy(&mru, data, sizeof(mru));
+           mru = ntohs(mru);
+           if (mru >= ETH_PPPOE_MTU) {
+               if (lcp_allowoptions[0].mru > mru)
+                   lcp_allowoptions[0].mru = mru;
+               if (lcp_wantoptions[0].mru > mru)
+                   lcp_wantoptions[0].mru = mru;
+               conn->seenMaxPayload = 1;
+           }
+       }
+       break;
     case TAG_SERVICE_NAME_ERROR:
        error("PADO: Service-Name-Error: %.*s", (int) len, data);
        conn->error = 1;
@@ -172,10 +188,24 @@ parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
              void *extra)
 {
     PPPoEConnection *conn = (PPPoEConnection *) extra;
+    UINT16_t mru;
     switch(type) {
     case TAG_SERVICE_NAME:
        dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
        break;
+    case TAG_PPP_MAX_PAYLOAD:
+       if (len == sizeof(mru)) {
+           memcpy(&mru, data, sizeof(mru));
+           mru = ntohs(mru);
+           if (mru >= ETH_PPPOE_MTU) {
+               if (lcp_allowoptions[0].mru > mru)
+                   lcp_allowoptions[0].mru = mru;
+               if (lcp_wantoptions[0].mru > mru)
+                   lcp_wantoptions[0].mru = mru;
+               conn->seenMaxPayload = 1;
+           }
+       }
+       break;
     case TAG_SERVICE_NAME_ERROR:
        error("PADS: Service-Name-Error: %.*s", (int) len, data);
        conn->error = 1;
@@ -259,6 +289,19 @@ sendPADI(PPPoEConnection *conn)
        plen += sizeof(pid) + TAG_HDR_SIZE;
     }
 
+    /* Add our maximum MTU/MRU */
+    if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+       PPPoETag maxPayload;
+       UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+       maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
+       maxPayload.length = htons(sizeof(mru));
+       memcpy(maxPayload.payload, &mru, sizeof(mru));
+       CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
+       memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
+       cursor += sizeof(mru) + TAG_HDR_SIZE;
+       plen += sizeof(mru) + TAG_HDR_SIZE;
+    }
+
     packet.length = htons(plen);
 
     sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
@@ -289,6 +332,7 @@ waitForPADO(PPPoEConnection *conn, int timeout)
     pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
     pc.seenACName    = 0;
     pc.seenServiceName = 0;
+    conn->seenMaxPayload = 0;
     conn->error = 0;
 
     do {
@@ -413,6 +457,19 @@ sendPADR(PPPoEConnection *conn)
        plen += sizeof(pid) + TAG_HDR_SIZE;
     }
 
+    /* Add our maximum MTU/MRU */
+    if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+       PPPoETag maxPayload;
+       UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+       maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
+       maxPayload.length = htons(sizeof(mru));
+       memcpy(maxPayload.payload, &mru, sizeof(mru));
+       CHECK_ROOM(cursor, packet.payload, sizeof(mru) + TAG_HDR_SIZE);
+       memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
+       cursor += sizeof(mru) + TAG_HDR_SIZE;
+       plen += sizeof(mru) + TAG_HDR_SIZE;
+    }
+
     /* Copy cookie and relay-ID if needed */
     if (conn->cookie.type) {
        CHECK_ROOM(cursor, packet.payload,
@@ -566,6 +623,14 @@ discovery(PPPoEConnection *conn)
        timeout *= 2;
     } while (conn->discoveryState == STATE_SENT_PADR);
 
+    if (!conn->seenMaxPayload) {
+       /* RFC 4638: MUST limit MTU/MRU to 1492 */
+       if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU)
+           lcp_allowoptions[0].mru = ETH_PPPOE_MTU;
+       if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU)
+           lcp_wantoptions[0].mru = ETH_PPPOE_MTU;
+    }
+
     /* We're done. */
     conn->discoveryState = STATE_SESSION;
     return;