diff options
| author | Denys Fedoryshchenko <denys.f@collabora.com> | 2026-07-07 00:51:40 +0300 |
|---|---|---|
| committer | Denys Fedoryshchenko <denys.f@collabora.com> | 2026-07-07 00:51:44 +0300 |
| commit | a9dd25763194f0df41f2a0c2b135f5c872886ae4 (patch) | |
| tree | b7504c320a58c93d5456bdf1370042d01a63e539 | |
| parent | 702eab1af49717924ba4009b89bbbeb9ed52066c (diff) | |
| download | accel-ppp-a9dd25763194f0df41f2a0c2b135f5c872886ae4.tar.gz accel-ppp-a9dd25763194f0df41f2a0c2b135f5c872886ae4.zip | |
ppp: don't terminate session on IPV6CP TermReq unless IPv6 is required
Some broken CPE routers (e.g. Phicomm KE2M, older Linksys) negotiate
IPV6CP successfully but then fail to configure IPv6 locally and send
IPV6CP TermReq while intending to keep using the session for IPv4.
accel-ppp currently terminates the whole session on any IPV6CP TermReq,
which violates the RFC 1661 section 3.7 implementation note:
"the fact that one NCP has Closed is not sufficient reason to cause
the termination of the PPP link, even if that NCP was the only NCP
currently in the Opened state."
Terminate the session only when ipv6=require. Otherwise mark the layer
passive so session bring-up can proceed if IPV6CP never started.
The TermReq handler change alone is not enough for these routers: they
send TermReq *after* IPV6CP has opened, so ipv6cp->started is already
set and ipv6cp_layer_finished() (reached via TermAck or the restart
timer once the FSM winds down through Stopping->Stopped) would still
kill the session through its started branch. Apply the same policy
there: only terminate if ipv6=require, otherwise log and keep the
session running IPv4-only.
In require mode the TermReq path still records TERM_USER_REQUEST as
before (and sets ses->terminating, so layer_finished doesn't override
the cause); TERM_USER_ERROR in layer_finished now only covers genuine
negotiation failures.
Based on the fix proposed by Marek Michalkiewicz and reworked by
Alarig Le Lay.
Closes: https://github.com/accel-ppp/accel-ppp/issues/57
Supersedes: https://github.com/accel-ppp/accel-ppp/pull/298
Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
| -rw-r--r-- | accel-pppd/ppp/ppp_ipv6cp.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/accel-pppd/ppp/ppp_ipv6cp.c b/accel-pppd/ppp/ppp_ipv6cp.c index 1194b314..7f278daa 100644 --- a/accel-pppd/ppp/ppp_ipv6cp.c +++ b/accel-pppd/ppp/ppp_ipv6cp.c @@ -205,8 +205,12 @@ static void ipv6cp_layer_finished(struct ppp_fsm_t *fsm) ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_ERROR, 0); else ppp_layer_passive(ipv6cp->ppp, &ipv6cp->ld); - } else if (!ipv6cp->ppp->ses.terminating) - ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_ERROR, 0); + } else if (!ipv6cp->ppp->ses.terminating) { + if (conf_ipv6 == IPV6_REQUIRE) + ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_ERROR, 0); + else + log_ppp_info1("ipv6cp: closed, session continues without IPv6\n"); + } fsm->fsm_state = FSM_Closed; } @@ -738,7 +742,12 @@ static void ipv6cp_recv(struct ppp_handler_t*h) if (conf_ppp_verbose) log_ppp_info2("recv [IPV6CP TermReq id=%x]\n", hdr->id); ppp_fsm_recv_term_req(&ipv6cp->fsm); - ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_REQUEST, 0); + /* RFC 1661 sec 3.7: closing one NCP is not sufficient reason + * to terminate the PPP link */ + if (conf_ipv6 == IPV6_REQUIRE) + ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_REQUEST, 0); + else + ppp_layer_passive(ipv6cp->ppp, &ipv6cp->ld); break; case TERMACK: if (conf_ppp_verbose) |
