I couldn't get the pppoe server to work on -current, rebuilt -current yesterday and it now works - user error.

The following works in all the combinations 5.0 client/server userland and with -current client/server and with -current pppoe(4).

-- ben



Index: client.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/client.c,v
retrieving revision 1.24
diff -u -p -r1.24 client.c
--- client.c    5 Nov 2011 09:20:36 -0000    1.24
+++ client.c    30 Jan 2012 22:35:46 -0000
@@ -50,6 +50,7 @@

 u_int32_t client_cookie;
 u_int16_t client_sessionid;
+u_int16_t client_mtu;
 int pppfd, client_state;

 static int getpackets(int, u_int8_t *, u_int8_t *, struct ether_addr *,
@@ -80,6 +81,7 @@ client_mode(int bfd, u_int8_t *sysname,
     pppfd = -1;
     client_sessionid = 0xffff;
     client_state = -1;
+    client_mtu = 0;

     r = send_padi(bfd, myea, srvname);
     if (r <= 0)
@@ -144,13 +146,14 @@ client_mode(int bfd, u_int8_t *sysname,
 static int
 send_padi(int fd, struct ether_addr *ea, u_int8_t *srv)
 {
-    struct iovec iov[10];
+    struct iovec iov[12];
     struct pppoe_header ph = {
         PPPOE_VERTYPE(1, 1),
         PPPOE_CODE_PADI, 0, 0
     };
-    struct pppoe_tag thost, tserv;
+    struct pppoe_tag thost, tserv, tmaxpayload;
     u_int16_t etype = htons(ETHERTYPE_PPPOEDISC);
+    u_int16_t maxpayload;
     int i = 0;

     /* ether_header */
@@ -190,6 +193,21 @@ send_padi(int fd, struct ether_addr *ea,
     }
     tserv.len = htons(tserv.len);

+    /* ppp-max-payload tag (optional) */
+    if (rfc_4638_mtu > PPPOE_MIN_MTU) {
+        tmaxpayload.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+        tmaxpayload.len = htons(sizeof(maxpayload));
+        tmaxpayload.val = (u_int8_t*) &maxpayload;
+        maxpayload = htons(rfc_4638_mtu);
+        iov[i].iov_base = &tmaxpayload;
+ iov[i++].iov_len = sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type);
+        iov[i].iov_base = &maxpayload;
+        iov[i++].iov_len = sizeof(maxpayload);
+        ph.len += sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type) +
+sizeof(maxpayload);
+    }
+
+
     ph.len = htons(ph.len);

     client_state = STATE_EXPECT_PADO;
@@ -202,9 +220,10 @@ send_padr(int bfd, u_int8_t *srv, struct
     struct ether_addr *rmea, struct ether_header *eh,
     struct pppoe_header *ph, struct tag_list *tl)
 {
-    struct iovec iov[12];
+    struct iovec iov[14];
     u_int16_t etype = htons(ETHERTYPE_PPPOEDISC);
-    struct pppoe_tag hutag, svtag;
+    struct pppoe_tag hutag, svtag, mptag;
+    u_int16_t maxpayload = htons(client_mtu);
     struct tag_node *n;
     int idx = 0, slen;

@@ -245,6 +264,18 @@ send_padr(int bfd, u_int8_t *srv, struct
         iov[idx++].iov_len = slen;
     }

+    /* PPP-Max-Payload */
+    if (client_mtu > 0) {
+        mptag.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+        mptag.len = htons(sizeof(maxpayload));
+        iov[idx].iov_base = &mptag;
+        iov[idx++].iov_len = sizeof(mptag.type) + sizeof(mptag.len);
+        iov[idx].iov_base = &maxpayload;
+        iov[idx++].iov_len = sizeof(maxpayload);
+ ph->len += sizeof(mptag.type) + sizeof(mptag.len) + sizeof(maxpayload);
+    }
+
+
     n = tag_lookup(tl, PPPOE_TAG_RELAY_SESSION, 0);
     if (n != NULL) {
         iov[idx].iov_base = &n->type;
@@ -407,6 +438,18 @@ recv_pado(int bfd, u_int8_t *srv, struct
     if (bcmp(n->val, &client_cookie, sizeof(client_cookie)))
         goto out;

+    n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+    if (n != NULL) {
+        client_mtu = n->val[1] | (n->val[0] << 8);
+        if (client_mtu > rfc_4638_mtu) {
+            client_mtu = rfc_4638_mtu;
+        } else if (client_mtu < PPPOE_MIN_MTU) {
+            client_mtu = PPPOE_MIN_MTU;
+        }
+    } else {
+        client_mtu = 0;
+    }
+
     r = 0;
     slen = (srv == NULL) ? 0 : strlen((char *)srv);
     while ((n = tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, r)) != NULL) {
@@ -462,6 +505,18 @@ recv_pads(int bfd, u_int8_t *srv, u_int8
         goto out;
     if (bcmp(n->val, &client_cookie, sizeof(client_cookie)))
         goto out;
+
+    n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+    if (n != NULL && n->len == sizeof(client_mtu)) {
+        client_mtu = n->val[1] | (n->val[0] << 8);
+        if (client_mtu > rfc_4638_mtu ||
+            client_mtu < PPPOE_MIN_MTU) {
+            /* error; fallback */
+            client_mtu = 0;
+        }
+    } else {
+        client_mtu = 0;
+    }

     if (ph->sessionid == 0) {
         timer_clr();
Index: common.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/common.c,v
retrieving revision 1.13
diff -u -p -r1.13 common.c
--- common.c    5 Nov 2011 09:20:36 -0000    1.13
+++ common.c    30 Jan 2012 22:35:46 -0000
@@ -138,7 +138,7 @@ ppp_to_bpf(int bfd, int pppfd, struct et
     int r;

     if (pktbuf == NULL) {
-        pktbuf = (u_int8_t *)malloc(PPPOE_MTU);
+        pktbuf = (u_int8_t *)malloc(rfc_4638_mtu + PPPOE_MTU_DIFF);
         if (pktbuf == NULL)
             return (-1);
     }
@@ -146,7 +146,7 @@ ppp_to_bpf(int bfd, int pppfd, struct et
     iov[0].iov_base = trash;
     iov[0].iov_len = 2;
     iov[1].iov_base = pktbuf;
-    iov[1].iov_len = PPPOE_MTU;
+    iov[1].iov_len = rfc_4638_mtu + PPPOE_MTU_DIFF;
     r = readv(pppfd, iov, 2);
     if (r <= 0)
         return (-1);
Index: debug.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/debug.c,v
retrieving revision 1.2
diff -u -p -r1.2 debug.c
--- debug.c    4 Jun 2003 04:46:13 -0000    1.2
+++ debug.c    30 Jan 2012 22:35:46 -0000
@@ -156,6 +156,9 @@ debug_packet(u_int8_t *pkt, int len)
         case PPPOE_TAG_RELAY_SESSION:
             printf("relay-session");
             break;
+        case PPPOE_TAG_PPP_MAX_PAYLOAD:
+            printf("ppp-max-payload");
+            break;
         case PPPOE_TAG_SERVICE_NAME_ERROR:
             printf("service-name-error");
             break;
Index: pppoe.8
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/pppoe.8,v
retrieving revision 1.24
diff -u -p -r1.24 pppoe.8
--- pppoe.8    20 Apr 2011 12:53:50 -0000    1.24
+++ pppoe.8    30 Jan 2012 22:35:46 -0000
@@ -37,6 +37,7 @@
 .Op Fl i Ar interface
 .Op Fl n Ar service
 .Op Fl p Ar system
+.Op Fl m Ar mtu
 .Sh DESCRIPTION
 The
 .Nm pppoe
@@ -67,6 +68,14 @@ This argument is passed, uninterpreted,
 It can be used to specify the configuration data to be used for
 PPP Over Ethernet connections.
 This option is only used in server mode.
+.It Fl m Ar mtu
+Attempt to negotiate a higher MTU, using RFC 4638.  It is your
+responsibility to ensure that the ethernet
+.Ar interface
+supports jumbo frames and is configured with an MTU at
+least 8 bytes greater than this or 1500, and that
+.Xr ppp 8
+is also configured to support the same maximum MTU/MRU.
 .It Fl s
 If this option is specified,
 .Nm
@@ -223,6 +232,13 @@ to adjust the maximum segment size on ou
 .%T A Method for Transmitting PPP Over Ethernet (PPPoE)
 .%A L. Mamakos, et al.
 .Re
+.Rs
+.%R RFC 4638
+.%T Accommodating a Maximum Transit Unit/Maximum Receive Unit
+(MTU/MRU) Greater Than 1492 in the Point-to-Point Protocol over
+Ethernet (PPPoE)
+.%A P. Arberg, et al.
+.Re
 .Sh HISTORY
 This implementation of
 .Nm pppoe
@@ -238,6 +254,11 @@ program was written by
 of
 .An Network Security Technologies, Inc.\&
 .Aq http://www.netsec.net .
+.Sh CAVEATS
+RFC 4638 negotiation is only aware of the MTU configured on the endpoints,
+but not the maximum MTU supported on the path between them.
+If the path cannot pass the larger Ethernet frames, negotiation will succeed
+but the connection will not function correctly.
 .Sh BUGS
 This software runs completely in user mode.
 As such it will have much more overhead than a kernel implementation.
Index: pppoe.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/pppoe.c,v
retrieving revision 1.19
diff -u -p -r1.19 pppoe.c
--- pppoe.c    5 Nov 2011 09:20:36 -0000    1.19
+++ pppoe.c    30 Jan 2012 22:35:46 -0000
@@ -46,9 +46,11 @@
 #include <sysexits.h>
 #include <signal.h>
 #include <ifaddrs.h>
+#include <stdlib.h>

 #include "pppoe.h"

+u_int16_t rfc_4638_mtu = PPPOE_MIN_MTU;
 int option_verbose = 0;
 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

@@ -72,10 +74,12 @@ main(int argc, char **argv)
     int bpffd, smode = 0, c;
     struct passwd *pw;

+    rfc_4638_mtu = PPPOE_MIN_MTU;
+
     if ((pw = getpwnam("_ppp")) == NULL)
         err(EX_CONFIG, "getpwnam(\"_ppp\")");

-    while ((c = getopt(argc, argv, "svi:n:p:")) != -1) {
+    while ((c = getopt(argc, argv, "svm:i:n:p:")) != -1) {
         switch (c) {
         case 'i':
             if (ifname != NULL) {
@@ -91,6 +95,11 @@ main(int argc, char **argv)
             }
             srvname = (u_int8_t *)optarg;
             break;
+        case 'm':
+            rfc_4638_mtu = (u_int16_t) atoi(optarg);
+            if (rfc_4638_mtu < PPPOE_MIN_MTU)
+                rfc_4638_mtu = PPPOE_MIN_MTU;
+            break;
         case 'p':
             if (sysname != NULL) {
                 usage();
@@ -412,6 +421,8 @@ getifhwaddr(char *ifnhint, char *ifnambu
 {
     struct sockaddr_dl *dl;
     struct ifaddrs *ifap, *ifa;
+    struct ifreq ifr;
+    int fd;

     if (getifaddrs(&ifap) != 0) {
         perror("getifaddrs");
@@ -442,6 +453,34 @@ getifhwaddr(char *ifnhint, char *ifnambu
             freeifaddrs(ifap);
             return (-1);
         }
+
+        /* check and reduce interface MTU per RFC 4638 */
+        if (rfc_4638_mtu > PPPOE_MIN_MTU) {
+            fd = socket(AF_INET, SOCK_DGRAM, 0);
+            if (fd == -1) {
+                rfc_4638_mtu = PPPOE_MIN_MTU;
+                goto choose;
+            }
+            strlcpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
+            if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) {
+                close(fd);
+                rfc_4638_mtu = PPPOE_MIN_MTU;
+                goto choose;
+            }
+            close(fd);
+            if (ifr.ifr_mtu < ETHERMTU) {
+                fprintf(stderr, "interface %s mtu %d too low\n",
+                    ifa->ifa_name, ifr.ifr_mtu);
+                freeifaddrs(ifap);
+                return (-1);
+            }
+            ifr.ifr_mtu -= 8;
+            if (rfc_4638_mtu > ifr.ifr_mtu) {
+                rfc_4638_mtu = ifr.ifr_mtu;
+            }
+        }
+
+choose:
         bcopy(dl->sdl_data + dl->sdl_nlen, ea, sizeof(*ea));
         strlcpy(ifnambuf, ifa->ifa_name, IFNAMSIZ);
         freeifaddrs(ifap);
@@ -461,7 +500,7 @@ usage(void)
     extern char *__progname;

     fprintf(stderr,
-        "usage: %s [-sv] [-i interface] [-n service] [-p system]\n",
+ "usage: %s [-sv] [-i interface] [-n service] [-p system] [-m mtu]\n",
         __progname);
 }

Index: pppoe.h
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/pppoe.h,v
retrieving revision 1.10
diff -u -p -r1.10 pppoe.h
--- pppoe.h    15 Oct 2011 02:05:07 -0000    1.10
+++ pppoe.h    30 Jan 2012 22:35:46 -0000
@@ -44,6 +44,8 @@ struct pppoe_header {
     u_int16_t len;        /* PPPoE payload length */
 };
 #define    PPPOE_MTU        (ETHERMTU - sizeof(struct pppoe_header))
+#define PPPOE_MTU_DIFF        2
+#define    PPPOE_MIN_MTU        (PPPOE_MTU - PPPOE_MTU_DIFF)

 #define    PPPOE_VER_S        0    /* Version shift */
 #define    PPPOE_VER_M        0x0f    /* Version mask */
@@ -76,10 +78,12 @@ struct pppoe_tag {
#define PPPOE_TAG_AC_COOKIE 0x0104 /* Access Concentratr Cookie */
 #define    PPPOE_TAG_VENDOR_SPEC        0x0105    /* Vendor Specific */
 #define    PPPOE_TAG_RELAY_SESSION        0x0110    /* Relay Session Id */
+#define PPPOE_TAG_PPP_MAX_PAYLOAD 0x0120 /* RFC 4638 PPP-Max-Payload */ #define PPPOE_TAG_SERVICE_NAME_ERROR 0x0201 /* Service Name Error */ #define PPPOE_TAG_AC_SYSTEM_ERROR 0x0202 /* Acc. Concentrator Error */
 #define    PPPOE_TAG_GENERIC_ERROR        0x0203    /* Generic Error */

+extern u_int16_t rfc_4638_mtu;    /* maximum value of mtu */
 extern int option_verbose;
 extern u_char etherbroadcastaddr[];

@@ -110,6 +114,7 @@ struct pppoe_session {
     struct ether_addr s_ea;        /* remote ethernet mac */
     u_int16_t s_id;            /* session id */
     int s_fd;            /* ttyfd */
+    u_int16_t s_mtu;        /* negotiated mtu */
 };

 struct pppoe_session_master {
Index: server.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/server.c,v
retrieving revision 1.15
diff -u -p -r1.15 server.c
--- server.c    5 Nov 2011 09:20:36 -0000    1.15
+++ server.c    30 Jan 2012 22:35:46 -0000
@@ -60,13 +60,17 @@ static void recv_padt(int, struct ether_
     struct ether_header *, struct pppoe_header *, u_long, u_int8_t *);

 static void send_pado(int, struct ether_addr *,
-    struct ether_header *, struct pppoe_header *, u_long, u_int8_t *);
+    struct ether_header *, struct pppoe_header *, u_long, u_int8_t *,
+    u_int16_t);
 static void send_pads(int, u_int8_t *, struct ether_addr *,
-    struct ether_header *, struct pppoe_header *, u_long, u_int8_t *);
+    struct ether_header *, struct pppoe_header *, u_long, u_int8_t *,
+    u_int16_t);
 static void key_gen(void);
 static u_int8_t *key_make(u_int8_t *, int, u_int8_t *, int);
 static int key_cmp(u_int8_t *, int, u_int8_t *, int, u_int8_t *, int);

+static u_long scrub_pkt(u_long, u_int8_t *);
+
 void
 server_mode(int bpffd, u_int8_t *sysname, u_int8_t *srvname,
     struct ether_addr *ea)
@@ -273,6 +277,8 @@ recv_padi(int bpffd, struct ether_addr *
     struct pppoe_header *ph, u_long pktlen, u_int8_t *pktbuf)
 {
     struct tag_list tl;
+    struct tag_node *n;
+    u_int16_t mtu = 0;

     if (ph->sessionid != 0)
         return;
@@ -286,7 +292,17 @@ recv_padi(int bpffd, struct ether_addr *
     if (tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, 1) != NULL)
         goto out;

-    send_pado(bpffd, ea, eh, ph, pktlen, pktbuf);
+    n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+    if (n != NULL && n->len == sizeof(mtu)) {
+        mtu = n->val[1] | (n->val[0] << 8);
+        if (mtu < PPPOE_MIN_MTU) {
+            mtu = PPPOE_MIN_MTU;
+        } else if (mtu > rfc_4638_mtu) {
+            mtu = rfc_4638_mtu;
+        }
+    }
+
+    send_pado(bpffd, ea, eh, ph, pktlen, pktbuf, mtu);

 out:
     tag_destroy(&tl);
@@ -294,12 +310,15 @@ out:

 static void
 send_pado(int bpffd, struct ether_addr *ea, struct ether_header *eh,
-    struct pppoe_header *ph, u_long pktlen, u_int8_t *pktbuf)
+    struct pppoe_header *ph, u_long pktlen, u_int8_t *pktbuf,
+    u_int16_t offer_mtu)
 {
-    struct pppoe_tag ktag, htag;
+    struct pppoe_tag ktag, htag, tmaxpayload, teol;
+    u_int16_t maxpayload;
+    u_long newlen;
     u_int8_t hn[MAXHOSTNAMELEN];
     u_int8_t *k = NULL;
-    struct iovec v[7];
+    struct iovec v[10];
     int idx = 0;

     memcpy(&eh->ether_dhost[0], &eh->ether_shost[0], ETHER_ADDR_LEN);
@@ -310,7 +329,13 @@ send_pado(int bpffd, struct ether_addr *
     ph->code = PPPOE_CODE_PADO;
     v[idx].iov_base = ph; v[idx].iov_len = sizeof(*ph); idx++;

-    v[idx].iov_base = pktbuf; v[idx].iov_len = pktlen; idx++;
+    /* Scrub unknown tags from the packet before returning them */
+    if ((newlen = scrub_pkt(pktlen, pktbuf)) == 0)
+        return;
+    if (newlen != pktlen)
+        ph->len -= pktlen - newlen;
+
+    v[idx].iov_base = pktbuf; v[idx].iov_len = newlen; idx++;

     if (gethostname((char *)hn, sizeof(hn)) < 0)
         return;
@@ -338,6 +363,28 @@ send_pado(int bpffd, struct ether_addr *
     ph->len += sizeof(ktag.len) + sizeof(ktag.type) + COOKIE_LEN;
     ktag.len = htons(COOKIE_LEN);

+    if (offer_mtu > 0) {
+                tmaxpayload.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+                tmaxpayload.len = sizeof(maxpayload);
+                tmaxpayload.val = (u_int8_t*) &maxpayload;
+                maxpayload = htons(offer_mtu);
+                v[idx].iov_base = &tmaxpayload;
+ v[idx].iov_len = sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type);
+        idx++;
+                v[idx].iov_base = &maxpayload;
+                v[idx].iov_len = sizeof(maxpayload);
+        idx++;
+ ph->len += sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type) + sizeof(maxpayload);
+        tmaxpayload.len = htons(tmaxpayload.len);
+    }
+
+    teol.type = htons(PPPOE_TAG_END_OF_LIST);
+    teol.len = 0;
+    v[idx].iov_base = &teol;
+    v[idx].iov_len = sizeof(teol.type) + sizeof(teol.len);
+    ph->len += v[idx].iov_len;
+    idx++;
+
     ph->len = htons(ph->len);

     writev(bpffd, v, idx);
@@ -353,6 +400,7 @@ recv_padr(int bpffd, u_int8_t *sysname,
 {
     struct tag_list tl;
     struct tag_node *n;
+    u_int16_t mtu = 0;

     if (ph->sessionid != 0)
         return;
@@ -368,7 +416,16 @@ recv_padr(int bpffd, u_int8_t *sysname,
         ac_cookie_key, sizeof(ac_cookie_key)))
         return;

-    send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf);
+    n = tag_lookup(&tl, PPPOE_TAG_PPP_MAX_PAYLOAD, 0);
+    if (n != NULL && n->len == sizeof(mtu)) {
+        mtu = n->val[1] | (n->val[0] << 8);
+        if (mtu > rfc_4638_mtu || mtu < PPPOE_MIN_MTU) {
+            /* error; fallback */
+                        mtu = PPPOE_MIN_MTU;
+        }
+    }
+
+    send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf, mtu);

     tag_destroy(&tl);
 }
@@ -376,12 +433,14 @@ recv_padr(int bpffd, u_int8_t *sysname,
 static void
 send_pads(int bpffd, u_int8_t *sysname, struct ether_addr *ea,
     struct ether_header *eh, struct pppoe_header *ph,
-    u_long pktlen, u_int8_t *pktbuf)
+    u_long pktlen, u_int8_t *pktbuf, u_int16_t final_mtu)
 {
+    u_long newlen;
     u_int8_t hn[MAXHOSTNAMELEN];
-    struct iovec v[16];
+    u_int16_t maxpayload;
+    struct iovec v[19];
     struct pppoe_session *s;
-    struct pppoe_tag htag;
+    struct pppoe_tag htag, tmaxpayload, teol;
     int idx = 0;

     s = session_new((struct ether_addr *)&eh->ether_shost[0]);
@@ -399,7 +458,13 @@ send_pads(int bpffd, u_int8_t *sysname,
         return;
     v[idx].iov_base = ph; v[idx].iov_len = sizeof(*ph); idx++;

-    v[idx].iov_base = pktbuf; v[idx].iov_len = pktlen; idx++;
+    /* Scrub unknown tags from the packet before returning them */
+    if ((newlen = scrub_pkt(pktlen, pktbuf)) == 0)
+        return;
+    if (newlen != pktlen)
+        ph->len -= pktlen - newlen;
+
+    v[idx].iov_base = pktbuf; v[idx].iov_len = newlen; idx++;

     htag.len = strlen((char *)hn);
     htag.type = htons(PPPOE_TAG_AC_NAME);
@@ -411,6 +476,29 @@ send_pads(int bpffd, u_int8_t *sysname,
     ph->len += sizeof(htag.len) + sizeof(htag.type) + htag.len;
     htag.len = htons(htag.len);

+        if (final_mtu > 0) {
+        s->s_mtu = final_mtu;
+                tmaxpayload.type = htons(PPPOE_TAG_PPP_MAX_PAYLOAD);
+                tmaxpayload.len = sizeof(maxpayload);
+                tmaxpayload.val = (u_int8_t*) &maxpayload;
+                maxpayload = htons(final_mtu);
+                v[idx].iov_base = &tmaxpayload;
+ v[idx].iov_len = sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type);
+        idx++;
+                v[idx].iov_base = &maxpayload;
+                v[idx].iov_len = sizeof(maxpayload);
+        idx++;
+ ph->len += sizeof(tmaxpayload.len) + sizeof(tmaxpayload.type) + sizeof(maxpayload);
+        tmaxpayload.len = htons(tmaxpayload.len);
+        }
+
+        teol.type = htons(PPPOE_TAG_END_OF_LIST);
+        teol.len = 0;
+        v[idx].iov_base = &teol;
+        v[idx].iov_len = sizeof(teol.type) + sizeof(teol.len);
+        ph->len += v[idx].iov_len;
+        idx++;
+
     ph->len = htons(ph->len);

     writev(bpffd, v, idx);
@@ -441,4 +529,62 @@ recv_padt(int bpffd, struct ether_addr *

 out:
     tag_destroy(&tl);
+}
+
+static u_long
+scrub_pkt(u_long pktlen, u_int8_t *pkt)
+{
+    u_long         newlen = 0;
+    u_int16_t     ttype, tlen;
+    u_int8_t    *p = pkt;
+
+    while (pktlen != 0) {
+        if (pktlen < sizeof(u_int16_t))
+            break;
+        ttype = pkt[1] | (pkt[0] << 8);
+        pkt += sizeof(u_int16_t);
+        pktlen -= sizeof(u_int16_t);
+
+        if (pktlen < sizeof(u_int16_t))
+            break;
+        tlen = pkt[1] | (pkt[0] << 8);
+        pkt += sizeof(u_int16_t);
+        pktlen -= sizeof(u_int16_t);
+
+        if (pktlen < tlen)
+            break;
+
+        pkt += tlen;
+        pktlen -= tlen;
+
+        switch (ttype) {
+
+            /* Echo these tags back to the client */
+        case PPPOE_TAG_SERVICE_NAME:
+        case PPPOE_TAG_AC_NAME:
+        case PPPOE_TAG_HOST_UNIQ:
+        case PPPOE_TAG_AC_COOKIE:
+        case PPPOE_TAG_VENDOR_SPEC:
+        case PPPOE_TAG_RELAY_SESSION:
+        case PPPOE_TAG_SERVICE_NAME_ERROR:
+        case PPPOE_TAG_AC_SYSTEM_ERROR:
+        case PPPOE_TAG_GENERIC_ERROR:
+            p = pkt;
+            newlen += sizeof(u_int16_t) + sizeof(u_int16_t) + tlen;
+            break;
+
+            /* Scrub these */
+        case PPPOE_TAG_END_OF_LIST:
+        case PPPOE_TAG_PPP_MAX_PAYLOAD:
+        default:
+            if (pktlen != 0)
+                bcopy(pkt, p, pktlen);
+            pkt = p;
+            break;
+        }
+    }
+
+    if (pktlen != 0)
+        return (0);
+    return (newlen);
 }
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/pppoe/session.c,v
retrieving revision 1.5
diff -u -p -r1.5 session.c
--- session.c    5 Nov 2011 09:20:36 -0000    1.5
+++ session.c    30 Jan 2012 22:35:46 -0000
@@ -83,6 +83,7 @@ session_new(struct ether_addr *ea)
     s->s_id = id;
     s->s_fd = -1;
     memcpy(&s->s_ea, ea, ETHER_ADDR_LEN);
+    s->s_mtu = PPPOE_MIN_MTU;
     LIST_INSERT_HEAD(&session_master.sm_sessions, s, s_next);

     return (s);

Reply via email to