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");