Skip to content

Commit

Permalink
net: l2: ppp: add initial support for PAP authentication
Browse files Browse the repository at this point in the history
This patch implements optional authentication phase, which is done
between link establishment and network phases. It is part of LCP option
negotiation to decide whether authentication is needed and which
protocol will be used. For now we add only PAP support and try to
negotiate it when some other protocol (e.g. CHAP or EAP) is proposed
earlier. For simplicity reason we only add one way authentication
support, which means that we try to authenticate to the other peer, but
do not require authentication from it.

This is an important step to make PPP work with cellular network modems,
because most of them require to provide username and password within PPP
authentication phase. Those credentials are used by modem to login to
cellular network. In most cases however it is enough to provide dummy
values, because they are not verified. For this reason and simplicity of
this patch we hardcode PAP Peer-ID and Password now.

Signed-off-by: Marcin Niestroj <[email protected]>
  • Loading branch information
mniestroj authored and jukkar committed Aug 18, 2020
1 parent adb7725 commit a542de4
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 5 deletions.
16 changes: 16 additions & 0 deletions include/net/ppp.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ struct lcp_options {

/** Maximum Receive Unit value */
uint16_t mru;

/** Which authentication protocol was negotiated (0 means none) */
uint16_t auth_proto;
};

struct ipcp_options {
Expand Down Expand Up @@ -427,6 +430,13 @@ struct ppp_context {
} ipv6cp;
#endif

#if defined(CONFIG_NET_L2_PPP_PAP)
struct {
/** Finite state machine for PAP */
struct ppp_fsm fsm;
} pap;
#endif

#if defined(CONFIG_NET_SHELL)
struct {
struct {
Expand Down Expand Up @@ -490,6 +500,12 @@ struct ppp_context {

/** IPV6CP open status (open / closed) */
uint16_t is_ipv6cp_open : 1;

/** PAP status (up / down) */
uint16_t is_pap_up : 1;

/** PAP open status (open / closed) */
uint16_t is_pap_open : 1;
};

/**
Expand Down
11 changes: 11 additions & 0 deletions subsys/net/ip/net_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -3571,6 +3571,17 @@ static int cmd_net_ppp_status(const struct shell *shell, size_t argc,
"yes" : "no");
#endif /* CONFIG_NET_IPV6 */

#if defined(CONFIG_NET_L2_PPP_PAP)
PR("PAP state : %s (%d)\n",
ppp_state_str(ctx->pap.fsm.state), ctx->pap.fsm.state);
PR("PAP retransmits : %u\n", ctx->pap.fsm.retransmits);
PR("PAP NACK loops : %u\n", ctx->pap.fsm.nack_loops);
PR("PAP NACKs recv : %u\n", ctx->pap.fsm.recv_nack_loops);
PR("PAP current id : %d\n", ctx->pap.fsm.id);
PR("PAP ACK received : %s\n", ctx->pap.fsm.ack_received ?
"yes" : "no");
#endif /* CONFIG_NET_L2_PPP_PAP */

#else
PR_INFO("Set %s to enable %s support.\n",
"CONFIG_NET_L2_PPP and CONFIG_NET_PPP", "PPP");
Expand Down
2 changes: 2 additions & 0 deletions subsys/net/l2/ppp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ endif()
if(CONFIG_NET_IPV6)
zephyr_library_sources_ifdef(CONFIG_NET_L2_PPP ipv6cp.c)
endif()

zephyr_library_sources_ifdef(CONFIG_NET_L2_PPP_PAP pap.c)
9 changes: 9 additions & 0 deletions subsys/net/l2/ppp/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ config NET_L2_PPP_OPTION_DNS_USE
help
Use the DNS servers negotiated in the IPCP configuration.

config NET_L2_PPP_AUTH_SUPPORT
bool

config NET_L2_PPP_PAP
bool "PAP authentication protocol"
select NET_L2_PPP_AUTH_SUPPORT
help
Enable support for PAP authentication protocol.

module = NET_L2_PPP
module-dep = NET_LOG
module-str = Log level for ppp L2 layer
Expand Down
4 changes: 4 additions & 0 deletions subsys/net/l2/ppp/fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ struct ppp_context *ppp_fsm_ctx(struct ppp_fsm *fsm)
#if defined(CONFIG_NET_IPV6)
} else if (fsm->protocol == PPP_IPV6CP) {
return CONTAINER_OF(fsm, struct ppp_context, ipv6cp.fsm);
#endif
#if defined(CONFIG_NET_L2_PPP_PAP)
} else if (fsm->protocol == PPP_PAP) {
return CONTAINER_OF(fsm, struct ppp_context, pap.fsm);
#endif
}

Expand Down
89 changes: 89 additions & 0 deletions subsys/net/l2/ppp/lcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,89 @@ static enum net_verdict lcp_handle(struct ppp_context *ctx,
return ppp_fsm_input(&ctx->lcp.fsm, PPP_LCP, pkt);
}

struct lcp_option_data {
bool auth_proto_present;
uint16_t auth_proto;
};

static const enum ppp_protocol_type lcp_supported_auth_protos[] = {
#if defined(CONFIG_NET_L2_PPP_PAP)
PPP_PAP,
#endif
};

static int lcp_auth_proto_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
void *user_data)
{
struct lcp_option_data *data = user_data;
int ret;
int i;

ret = net_pkt_read_be16(pkt, &data->auth_proto);
if (ret < 0) {
/* Should not happen, is the pkt corrupt? */
return -EMSGSIZE;
}

NET_DBG("[LCP] Received auth protocol %x (%s)",
(unsigned int) data->auth_proto,
ppp_proto2str(data->auth_proto));

for (i = 0; i < ARRAY_SIZE(lcp_supported_auth_protos); i++) {
if (data->auth_proto == lcp_supported_auth_protos[i]) {
data->auth_proto_present = true;
return 0;
}
}

return -EINVAL;
}

static int lcp_auth_proto_nack(struct ppp_fsm *fsm, struct net_pkt *ret_pkt,
void *user_data)
{
(void)net_pkt_write_u8(ret_pkt, LCP_OPTION_AUTH_PROTO);
(void)net_pkt_write_u8(ret_pkt, 4);
return net_pkt_write_be16(ret_pkt, PPP_PAP);
}

static const struct ppp_peer_option_info lcp_peer_options[] = {
PPP_PEER_OPTION(LCP_OPTION_AUTH_PROTO, lcp_auth_proto_parse,
lcp_auth_proto_nack),
};

static int lcp_config_info_req(struct ppp_fsm *fsm,
struct net_pkt *pkt,
uint16_t length,
struct net_pkt *ret_pkt)
{
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
lcp.fsm);
struct lcp_option_data data = {
.auth_proto_present = false,
};
int ret;

ret = ppp_config_info_req(fsm, pkt, length, ret_pkt, PPP_LCP,
lcp_peer_options,
ARRAY_SIZE(lcp_peer_options),
&data);
if (ret != PPP_CONFIGURE_ACK) {
/* There are some issues with configuration still */
return ret;
}

ctx->lcp.peer_options.auth_proto = data.auth_proto;

if (data.auth_proto_present) {
NET_DBG("Authentication protocol negotiated: %x (%s)",
(unsigned int) data.auth_proto,
ppp_proto2str(data.auth_proto));
}

return PPP_CONFIGURE_ACK;
}

static void lcp_lower_down(struct ppp_context *ctx)
{
ppp_fsm_lower_down(&ctx->lcp.fsm);
Expand Down Expand Up @@ -88,6 +171,9 @@ static void lcp_down(struct ppp_fsm *fsm)
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
lcp.fsm);

memset(&ctx->lcp.peer_options.auth_proto, 0,
sizeof(ctx->lcp.peer_options.auth_proto));

ppp_link_down(ctx);

ppp_change_phase(ctx, PPP_ESTABLISH);
Expand Down Expand Up @@ -134,6 +220,9 @@ static void lcp_init(struct ppp_context *ctx)
ctx->lcp.fsm.cb.down = lcp_down;
ctx->lcp.fsm.cb.starting = lcp_starting;
ctx->lcp.fsm.cb.finished = lcp_finished;
if (IS_ENABLED(CONFIG_NET_L2_PPP_AUTH_SUPPORT)) {
ctx->lcp.fsm.cb.config_info_req = lcp_config_info_req;
}
ctx->lcp.fsm.cb.proto_extension = lcp_handle_ext;
}

Expand Down
39 changes: 34 additions & 5 deletions subsys/net/l2/ppp/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,49 @@ static void do_network(struct ppp_context *ctx)
}
}

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

ppp_change_phase(ctx, PPP_AUTH);
do_auth(ctx);

/* If no authentication is need, then we are done */
/* TODO: check here if auth is needed */
lcp_up(ctx);
}

do_network(ctx);
void ppp_link_authenticated(struct ppp_context *ctx)
{
NET_DBG("[%p] Link authenticated", ctx);

lcp_up(ctx);
do_network(ctx);
}

void ppp_link_terminated(struct ppp_context *ctx)
Expand Down
141 changes: 141 additions & 0 deletions subsys/net/l2/ppp/pap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2019-2020 Grinn
*
* 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_pkt.h>

#include "ppp_internal.h"

static enum net_verdict pap_handle(struct ppp_context *ctx,
struct net_if *iface,
struct net_pkt *pkt)
{
return ppp_fsm_input(&ctx->pap.fsm, PPP_PAP, pkt);
}

static struct net_pkt *pap_config_info_add(struct ppp_fsm *fsm)
{
uint8_t payload[] = { 5, 'b', 'l', 'a', 'n', 'k',
5, 'b', 'l', 'a', 'n', 'k' };
struct net_pkt *pkt;

pkt = net_pkt_alloc_with_buffer(ppp_fsm_iface(fsm), sizeof(payload),
AF_UNSPEC, 0, PPP_BUF_ALLOC_TIMEOUT);
if (!pkt) {
return NULL;
}

(void)net_pkt_write(pkt, payload, sizeof(payload));

return pkt;
}

static int pap_config_info_ack(struct ppp_fsm *fsm,
struct net_pkt *pkt,
uint16_t length)
{
/*
* We only support one way negotiation for now, so move to ACK_SENT
* phase right away.
*/
if (fsm->state == PPP_REQUEST_SENT) {
ppp_change_state(fsm, PPP_ACK_SENT);
}

return 0;
}

static void pap_lower_down(struct ppp_context *ctx)
{
ppp_fsm_lower_down(&ctx->pap.fsm);
}

static void pap_lower_up(struct ppp_context *ctx)
{
ppp_fsm_lower_up(&ctx->pap.fsm);
}

static void pap_open(struct ppp_context *ctx)
{
ppp_fsm_open(&ctx->pap.fsm);
}

static void pap_close(struct ppp_context *ctx, const uint8_t *reason)
{
ppp_fsm_close(&ctx->pap.fsm, reason);
}

static void pap_up(struct ppp_fsm *fsm)
{
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
pap.fsm);

if (ctx->is_pap_up) {
return;
}

ctx->is_pap_up = true;

NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
ppp_state_str(fsm->state), fsm->state);

ppp_link_authenticated(ctx);
}

static void pap_down(struct ppp_fsm *fsm)
{
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
pap.fsm);

if (!ctx->is_pap_up) {
return;
}

ctx->is_pap_up = false;
}

static void pap_finished(struct ppp_fsm *fsm)
{
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
pap.fsm);

if (!ctx->is_pap_open) {
return;
}

ctx->is_pap_open = false;
}

static void pap_proto_reject(struct ppp_fsm *fsm)
{
ppp_fsm_lower_down(fsm);
}

static void pap_init(struct ppp_context *ctx)
{
NET_DBG("proto %s (0x%04x) fsm %p", ppp_proto2str(PPP_PAP), PPP_PAP,
&ctx->pap.fsm);

memset(&ctx->pap.fsm, 0, sizeof(ctx->pap.fsm));

ppp_fsm_init(&ctx->pap.fsm, PPP_PAP);

ppp_fsm_name_set(&ctx->pap.fsm, ppp_proto2str(PPP_PAP));

ctx->pap.fsm.cb.up = pap_up;
ctx->pap.fsm.cb.down = pap_down;
ctx->pap.fsm.cb.finished = pap_finished;
ctx->pap.fsm.cb.proto_reject = pap_proto_reject;
ctx->pap.fsm.cb.config_info_add = pap_config_info_add;
ctx->pap.fsm.cb.config_info_ack = pap_config_info_ack;
}

PPP_PROTOCOL_REGISTER(PAP, PPP_PAP,
pap_init, pap_handle,
pap_lower_up, pap_lower_down,
pap_open, pap_close);
Loading

0 comments on commit a542de4

Please sign in to comment.