zephyr/subsys/net/l2/ppp/link.c
Marcin Niestroj 4c8d1496ea net: l2: ppp: don't move back to NETWORK state when link goes down
PPP Phase Diagram [1] allows only one way phase change. In current
implementation there is an additional RUNNING phase, which is entered
just after NETWORK phase.

Prevent going back from RUNNING to NETWORK phase when Term-Req was
received, as this is meaningless for overall PPP operation and violates
PPP Phase Diagram property of having one way direction change.

This change also improves Adminitrative Close handling (calling
lcp_close()). This request results in moving into TERMINATE phase. Then
LCP is put down (by calling lcp_down()) and then ppp_link_down() is
called, which so far (before this patch) resulted in moving back to
NETWORK and then to DEAD. Right now (after this patch) we move directly
from TERMINATE to DEAD phase, which is exactly how [1] specifies it.

[1] https://tools.ietf.org/html/rfc1661#section-3.2

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2020-08-21 11:53:59 +03:00

143 lines
2.6 KiB
C

/*
* Copyright (c) 2019 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
#include <net/net_core.h>
#include <net/net_pkt.h>
#include <net/ppp.h>
#include "net_private.h"
#include "ppp_internal.h"
static void lcp_up(struct ppp_context *ctx)
{
Z_STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) {
if (proto->protocol == PPP_LCP) {
continue;
}
if (proto->lower_up) {
proto->lower_up(ctx);
}
}
}
static void do_network(struct ppp_context *ctx)
{
ppp_change_phase(ctx, PPP_NETWORK);
Z_STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) {
if (proto->protocol == PPP_CCP || proto->protocol == PPP_ECP) {
if (proto->open) {
proto->open(ctx);
}
}
}
/* Do the other network protocols if encryption is not needed for
* them.
*/
/* TODO possible encryption stuff here*/
Z_STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) {
if (proto->protocol == PPP_CCP || proto->protocol == PPP_ECP ||
proto->protocol >= 0xC000) {
continue;
}
if (proto->open) {
ctx->network_protos_open++;
proto->open(ctx);
}
}
if (ctx->network_protos_open == 0) {
const struct ppp_protocol_handler *proto = ppp_lcp_get();
if (proto) {
proto->close(ctx, "No network protocols open");
}
}
}
static void do_auth(struct ppp_context *ctx)
{
uint16_t auth_proto = 0;
ppp_change_phase(ctx, PPP_AUTH);
if (IS_ENABLED(CONFIG_NET_L2_PPP_AUTH_SUPPORT)) {
auth_proto = ctx->lcp.peer_options.auth_proto;
}
/* If no authentication is need, then we are done */
if (!auth_proto) {
ppp_link_authenticated(ctx);
return;
}
Z_STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) {
if (proto->protocol == auth_proto) {
if (proto->open) {
proto->open(ctx);
}
break;
}
}
}
void ppp_link_established(struct ppp_context *ctx, struct ppp_fsm *fsm)
{
NET_DBG("[%p] Link established", ctx);
ppp_change_phase(ctx, PPP_ESTABLISH);
do_auth(ctx);
lcp_up(ctx);
}
void ppp_link_authenticated(struct ppp_context *ctx)
{
NET_DBG("[%p] Link authenticated", ctx);
do_network(ctx);
}
void ppp_link_terminated(struct ppp_context *ctx)
{
if (ctx->phase == PPP_DEAD) {
return;
}
/* TODO: cleanup things etc here if needed */
ppp_change_phase(ctx, PPP_DEAD);
NET_DBG("[%p] Link terminated", ctx);
}
void ppp_link_down(struct ppp_context *ctx)
{
if (ctx->phase == PPP_DEAD) {
return;
}
ppp_network_all_down(ctx);
ppp_change_phase(ctx, PPP_DEAD);
}
void ppp_link_needed(struct ppp_context *ctx)
{
/* TODO: Try to create link if needed. */
}