* Matt Dainty <m...@bodgit-n-scarper.com> [2012-01-02 16:30:55]:
> * Stuart Henderson <s...@spacehopper.org> [2011-12-31 10:12:41]:
> > 
> > If the remote side doesn't echo our tag back, we should restrict ourselves
> > to PPPOE_MAXMTU.
> > 
> > Certainly until we are checking this I think we should avoid automatically
> > raising pppoe(4)'s MTU based on pppoedev's MTU and require it to be set
> > explicitly on the pppoe iface (as well as the parent iface).
> 
> Attached is an updated patch for sys/net/if_pppoe.c that now tracks if
> the remote end echoes back the max payload tag that we will have sent.
> 
> However I'm not sure how best to set pppoe(4)'s MTU back down to
> PPPOE_MAXMTU (given all the extra logic is keyed off this value). Can I
> just set sc->sc_sppp.pp_if.if_mtu directly or should I bounce it
> through pppoe_ioctl() with SIOCSIFMTU? I can then update the patch and
> replace the FIXME with whatever code is necessary.

So once I stopped pppoe(8) from blindly agreeing to any increased MTU I
requested, I've now tested the below patches using an em(4) with a 1508
MTU against a server that doesn't support the larger MTU, pppoe0 will
now be set back to 1492 and PPP/LCP negotiation continues with the
correct MRU option. My Huawei/BT modem still negotiates the increased
size and PPP/LCP negotiation continues with the larger 1500 MRU. All
verified with some tcpdump captures.

I noticed "our" if_spppsubr.c compared to NetBSD's (re)sets the MRU
variables in sppp_lcp_up() so I moved the changes from sppp_lcp_open()
to there to prevent duplication and also fixed a small amount of
whitespace formatting (s/^ \t/\t/).

Comments?

Matt

--- sys/net/if_pppoe.c.orig     Tue Dec 13 21:52:04 2011
+++ sys/net/if_pppoe.c  Thu Jan  5 15:03:03 2012
@@ -86,6 +86,7 @@
 #define        PPPOE_TAG_ACCOOKIE      0x0104          /* AC cookie */
 #define        PPPOE_TAG_VENDOR        0x0105          /* vendor specific */
 #define        PPPOE_TAG_RELAYSID      0x0110          /* relay session id */
+#define        PPPOE_TAG_MAX_PAYLOAD   0x0120          /* RFC 4638 max payload 
*/
 #define        PPPOE_TAG_SNAME_ERR     0x0201          /* service name error */
 #define        PPPOE_TAG_ACSYS_ERR     0x0202          /* AC system error */
 #define        PPPOE_TAG_GENERIC_ERR   0x0203          /* gerneric error */
@@ -398,6 +399,7 @@
        size_t ac_cookie_len;
        size_t relay_sid_len;
        int noff, err, errortag;
+       u_int16_t *max_payload;
        u_int16_t tag, len;
        u_int16_t session, plen;
        u_int8_t *ac_cookie;
@@ -424,6 +426,7 @@
        ac_cookie_len = 0;
        relay_sid = NULL;
        relay_sid_len = 0;
+       max_payload = NULL;
 #ifdef PPPOE_SERVER
        hunique = NULL;
        hunique_len = 0;
@@ -531,6 +534,18 @@
                                relay_sid_len = len;
                        }
                        break;
+               case PPPOE_TAG_MAX_PAYLOAD:
+                       if (max_payload == NULL) {
+                               n = m_pulldown(m, off, len,
+                                   &noff);
+                               if (n == NULL || len != 2) {
+                                       err_msg = "TAG MAX_PAYLOAD ERROR";
+                                       m = NULL;
+                                       break;
+                               }
+                               max_payload = (u_int16_t *)(mtod(n, caddr_t) + 
noff);
+                       }
+                       break;
                case PPPOE_TAG_SNAME_ERR:
                        err_msg = "SERVICE NAME ERROR";
                        errortag = 1;
@@ -679,6 +694,13 @@
                        sc->sc_relay_sid_len = relay_sid_len;
                        memcpy(sc->sc_relay_sid, relay_sid, relay_sid_len);
                }
+               if (sc->sc_sppp.pp_if.if_mtu > PPPOE_MAXMTU &&
+                   (max_payload == NULL ||
+                    ntohs(*max_payload) != sc->sc_sppp.pp_if.if_mtu)) {
+                       printf("%s: No valid PPP-Max-Payload tag received in 
PADO\n",
+                           sc->sc_sppp.pp_if.if_xname);
+                       sc->sc_sppp.pp_if.if_mtu = PPPOE_MAXMTU;
+               }
                
                memcpy(&sc->sc_dest, eh->ether_shost, sizeof(sc->sc_dest));
                sc->sc_padr_retried = 0;
@@ -911,7 +933,7 @@
                                return (ENXIO);
                        }
 
-                       if (sc->sc_sppp.pp_if.if_mtu >
+                       if (sc->sc_sppp.pp_if.if_mtu !=
                            eth_if->if_mtu - PPPOE_OVERHEAD) {
                                sc->sc_sppp.pp_if.if_mtu = eth_if->if_mtu -
                                    PPPOE_OVERHEAD;
@@ -1068,6 +1090,8 @@
                l2 = strlen(sc->sc_concentrator_name);
                len += 2 + 2 + l2;
        }
+       if (sc->sc_sppp.pp_if.if_mtu > PPPOE_MAXMTU)
+               len += 2 + 2 + 2;
 
        /* allocate a buffer */
        m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN);     /* header len + payload 
len */
@@ -1094,9 +1118,15 @@
        PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
        PPPOE_ADD_16(p, sizeof(sc->sc_unique));
        memcpy(p, &sc->sc_unique, sizeof(sc->sc_unique));
+       p += sizeof(sc->sc_unique);
 
+       if (sc->sc_sppp.pp_if.if_mtu > PPPOE_MAXMTU) {
+               PPPOE_ADD_16(p, PPPOE_TAG_MAX_PAYLOAD);
+               PPPOE_ADD_16(p, 2);
+               PPPOE_ADD_16(p, (u_int16_t)sc->sc_sppp.pp_if.if_mtu);
+       }
+
 #ifdef PPPOE_DEBUG
-       p += sizeof(sc->sc_unique);
        if (p - mtod(m0, u_int8_t *) != len + PPPOE_HEADERLEN)
                panic("pppoe_send_padi: garbled output len, should be %ld, is 
%ld",
                    (long)(len + PPPOE_HEADERLEN), (long)(p - mtod(m0, u_int8_t 
*)));
@@ -1298,6 +1328,8 @@
                len += 2 + 2 + sc->sc_ac_cookie_len;    /* AC cookie */
        if (sc->sc_relay_sid_len > 0)
                len += 2 + 2 + sc->sc_relay_sid_len;    /* Relay SID */
+       if (sc->sc_sppp.pp_if.if_mtu > PPPOE_MAXMTU)
+               len += 2 + 2 + 2;
 
        m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN);
        if (m0 == NULL)
@@ -1329,9 +1361,15 @@
        PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
        PPPOE_ADD_16(p, sizeof(sc->sc_unique));
        memcpy(p, &sc->sc_unique, sizeof(sc->sc_unique));
+       p += sizeof(sc->sc_unique);
 
+       if (sc->sc_sppp.pp_if.if_mtu > PPPOE_MAXMTU) {
+               PPPOE_ADD_16(p, PPPOE_TAG_MAX_PAYLOAD);
+               PPPOE_ADD_16(p, 2);
+               PPPOE_ADD_16(p, (u_int16_t)sc->sc_sppp.pp_if.if_mtu);
+       }
+
 #ifdef PPPOE_DEBUG
-       p += sizeof(sc->sc_unique);
        if (p - mtod(m0, u_int8_t *) != len + PPPOE_HEADERLEN)
                panic("pppoe_send_padr: garbled output len, should be %ld, is 
%ld",
                        (long)(len + PPPOE_HEADERLEN), (long)(p - mtod(m0, 
u_int8_t *)));
--- sys/net/if_spppsubr.c.orig  Tue Dec 13 22:16:00 2011
+++ sys/net/if_spppsubr.c       Mon Jan  9 23:42:04 2012
@@ -2059,11 +2059,16 @@
                return;
        }
 
-       sp->pp_alivecnt = 0;
-       sp->lcp.opts = (1 << LCP_OPT_MAGIC);
-       sp->lcp.magic = 0;
-       sp->lcp.protos = 0;
-       sp->lcp.mru = sp->lcp.their_mru = sp->pp_if.if_mtu;
+       sp->pp_alivecnt = 0;
+       sp->lcp.opts = (1 << LCP_OPT_MAGIC);
+       sp->lcp.magic = 0;
+       sp->lcp.protos = 0;
+       if (sp->pp_if.if_mtu != PP_MTU) {
+               sp->lcp.mru = sp->pp_if.if_mtu;
+               sp->lcp.opts |= (1 << LCP_OPT_MRU);
+       } else
+               sp->lcp.mru = PP_MTU;
+       sp->lcp.their_mru = PP_MTU;
 
        getmicrouptime(&tv);
        sp->pp_last_receive = sp->pp_last_activity = tv.tv_sec;

Reply via email to