On 2012/01/31 23:53, Ben Gould wrote:
> 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

fixed diff (linewrapping and some spaces->tabs and 80-column
formatting in the diff itself), otherwise untested so far.


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    1 Feb 2012 02:34:04 -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,22 @@ 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 +221,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 +265,19 @@ 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 +440,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 +507,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    1 Feb 2012 02:34:04 -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     1 Feb 2012 02:34:04 -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     1 Feb 2012 02:34:04 -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     1 Feb 2012 02:34:04 -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     1 Feb 2012 02:34:04 -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    1 Feb 2012 02:34:04 -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,30 @@ 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 +402,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 +418,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 +435,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 +460,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 +478,31 @@ 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 +533,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   1 Feb 2012 02:34:04 -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