zephyr/subsys/net/l2/ppp/link.c
Bjarki Arge Andreasen 52be26a8e3 net: l2: ppp: Patch carrier lost and L2 enable/disable
L2 PPP is not able to handle the carrier being lost gracefully,
nor is it able to gracefully close the PPP connection when
net_if_down() is called.

This patch refactors the L2 PPP module to use the carrier state
to either properly close or simply terminate the PPP connection.

Additionally, it ensures that the PPP session is closed properly
before calling ppp->stop().

Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
2024-01-19 09:47:33 +01:00

147 lines
2.7 KiB
C

/*
* Copyright (c) 2019 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
#include <zephyr/net/net_core.h>
#include <zephyr/net/net_pkt.h>
#include <zephyr/sys/iterable_sections.h>
#include <zephyr/net/ppp.h>
#include "net_private.h"
#include "ppp_internal.h"
static void lcp_up(struct ppp_context *ctx)
{
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);
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*/
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;
}
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)
{
k_sem_give(&ctx->wait_ppp_link_terminated);
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)
{
k_sem_give(&ctx->wait_ppp_link_down);
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. */
}