If the underlying link's MTU is less than PP_MTU (e.g. PPPoE), set our
MRU to the link's MTU and initiate an MRU negotiation with the peer. This is useful when the PPP session is bridged from Ethernet to ATM by an ADSL modem (such as the Linksys AM200). Unless we negotiate the lower MRU, the peer is unaware that 1500-byte packets will not make it umolested across the link (the Linksys AM200 silently truncates them to 1498 bytes, creating a nice PMTU blackhole). Note that the PPP RFC says peers MUST accept 1500 byte packets, regardless of the negotiated MRU, so most ISPs which use PPPoA will probably still send 1500-byte packets. However, I persuaded my ISP (Andrews and Arnold) to modify their software to generate an ICMP error "fragment needed" for packets with IP.DF set which are larger than the negotiated MRU. They will still forward non-IP.DF packets, with the associated truncation, but at least my PMTU troubles have gone.
This commit is contained in:
parent
616f645161
commit
2346befecc
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: if_spppsubr.c,v 1.104 2007/03/04 06:03:16 christos Exp $ */
|
||||
/* $NetBSD: if_spppsubr.c,v 1.105 2007/06/23 08:45:25 scw Exp $ */
|
||||
|
||||
/*
|
||||
* Synchronous PPP/Cisco link level subroutines.
|
||||
|
@ -41,7 +41,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.104 2007/03/04 06:03:16 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.105 2007/06/23 08:45:25 scw Exp $");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_ipx.h"
|
||||
|
@ -1075,7 +1075,8 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
|||
#define ifr_mtu ifr_metric
|
||||
#endif
|
||||
case SIOCSIFMTU:
|
||||
if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru) {
|
||||
if (ifr->ifr_mtu < PPP_MINMRU ||
|
||||
ifr->ifr_mtu > sp->lcp.their_mru) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
@ -1085,7 +1086,8 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
|||
#endif
|
||||
#ifdef SLIOCSETMTU
|
||||
case SLIOCSETMTU:
|
||||
if (*(short *)data < 128 || *(short *)data > sp->lcp.their_mru)
|
||||
if (*(short *)data < PPP_MINMRU ||
|
||||
*(short *)data > sp->lcp.their_mru)
|
||||
{
|
||||
error = EINVAL;
|
||||
break;
|
||||
|
@ -2007,7 +2009,12 @@ sppp_lcp_init(struct sppp *sp)
|
|||
sp->pp_seq[IDX_LCP] = 0;
|
||||
sp->pp_rseq[IDX_LCP] = 0;
|
||||
sp->lcp.protos = 0;
|
||||
sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
|
||||
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;
|
||||
|
||||
/*
|
||||
* Initialize counters and timeout values. Note that we don't
|
||||
|
@ -2394,11 +2401,18 @@ sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
|
|||
break;
|
||||
case LCP_OPT_MRU:
|
||||
/*
|
||||
* Should not be rejected anyway, since we only
|
||||
* negotiate a MRU if explicitly requested by
|
||||
* peer.
|
||||
* We try to negotiate a lower MRU if the underlying
|
||||
* link's MTU is less than PP_MTU (e.g. PPPoE). If the
|
||||
* peer rejects this lower rate, fallback to the
|
||||
* default.
|
||||
*/
|
||||
if (debug) {
|
||||
addlog("%s: warning: peer rejected our MRU of "
|
||||
"%ld bytes. Defaulting to %d bytes\n",
|
||||
ifp->if_xname, sp->lcp.mru, PP_MTU);
|
||||
}
|
||||
sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
|
||||
sp->lcp.mru = PP_MTU;
|
||||
break;
|
||||
case LCP_OPT_AUTH_PROTO:
|
||||
/*
|
||||
|
@ -2494,8 +2508,8 @@ sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
|
|||
u_int mru = p[2] * 256 + p[3];
|
||||
if (debug)
|
||||
addlog(" %d", mru);
|
||||
if (mru < PP_MTU || mru > PP_MAX_MRU)
|
||||
mru = PP_MTU;
|
||||
if (mru < PPP_MINMRU || mru > sp->pp_if.if_mtu)
|
||||
mru = sp->pp_if.if_mtu;
|
||||
sp->lcp.mru = mru;
|
||||
sp->lcp.opts |= (1 << LCP_OPT_MRU);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue