Attached are three patches for RFC 4638 PPPoE support. The first two are for pppoe(4) based on similar changes made to NetBSD. The third patch is to tcpdump(8) so it recognises the additional tag type.
I've been running this on my Soekris net6501 with one of the the built in em(4) chips hooked up to the BT Openreach-branded Huawei modem. My /etc/hostname.em0 contains: mtu 1508 up and /etc/hostname.pppoe0 is configured as normal. Once up and running the network interfaces look like this: em0: flags=28843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,NOINET6> mtu 1508 lladdr be:ef:be:ef:be:ef priority: 0 media: Ethernet autoselect (100baseTX full-duplex,rxpause,txpause) status: active pppoe0: flags=28851<UP,POINTOPOINT,RUNNING,SIMPLEX,MULTICAST,NOINET6> mtu 1500 priority: 0 dev: em0 state: session sid: 0x903 PADI retries: 3 PADR retries: 0 time: 00:28:27 sppp: phase network authproto chap groups: pppoe egress status: active inet 1.2.3.4 --> 5.6.7.8 netmask 0xffffffff I'm aware the patch as it currently stands assumes the other end will JFW and agree to the increased size (as does the NetBSD code). I wasn't sure how best to handle the case when the remote end doesn't send the max payload tag back in the PADO/PADS packets. Matt --- sys/net/if_pppoe.c.orig Tue Dec 13 21:52:04 2011 +++ sys/net/if_pppoe.c Sat Dec 17 23:12:43 2011 @@ -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 /* 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 */ @@ -531,6 +532,8 @@ relay_sid_len = len; } break; + case PPPOE_TAG_MAX_PAYLOAD: + break; /* ignored */ case PPPOE_TAG_SNAME_ERR: err_msg = "SERVICE NAME ERROR"; errortag = 1; @@ -911,7 +914,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 +1071,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 +1099,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 +1309,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 +1342,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 Tue Dec 13 22:26:23 2011 @@ -2027,7 +2027,6 @@ sp->state[IDX_LCP] = STATE_INITIAL; sp->fail_counter[IDX_LCP] = 0; sp->lcp.protos = 0; - sp->lcp.mru = sp->lcp.their_mru = sp->pp_if.if_mtu; /* * Initialize counters and timeout values. Note that we don't @@ -2137,6 +2136,13 @@ HIDE void sppp_lcp_open(struct sppp *sp) { + 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; + /* * If we are authenticator, negotiate LCP_AUTH */ --- usr.sbin/tcpdump/print-ppp.c.orig Sat Feb 20 18:02:33 2010 +++ usr.sbin/tcpdump/print-ppp.c Tue Dec 13 21:46:33 2011 @@ -240,6 +240,7 @@ #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_MAX_PAYLOAD 0x0120 /* RFC 4638 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 */ @@ -883,6 +884,9 @@ break; case PPPOE_TAG_RELAY_SESSION: printf("Relay-Session"); + break; + case PPPOE_TAG_MAX_PAYLOAD: + printf("PPP-Max-Payload"); break; case PPPOE_TAG_SERVICE_NAME_ERROR: printf("Service-Name-Error");