net: ppp: dialup enablers

Introducing PPP dialup features to enable e.g. usage of nrf9160
based board as a dialup modem for transferring ip data over PPP
 (e.g. windows dial up), i.e. usage of Zephyr PPP as a server for
 providing MTU/MRU, IP address and DNS addresses for a PC:
- PPP LCP MRU option (configurable)
- PPP server: IPCP ip and dns address peer options to enable
providing IP and DNS addresses for PPP peer.

Signed-off-by: Jani Hirsimäki <jani.hirsimaki@nordicsemi.no>
This commit is contained in:
Jani Hirsimäki 2021-03-25 14:00:28 +02:00 committed by Jukka Rissanen
commit 5d76e8aca8
6 changed files with 231 additions and 2 deletions

View file

@ -23,6 +23,12 @@ config NET_PPP_DRV_NAME
help
This option sets the driver name
config NET_PPP_MTU_MRU
int "PPP MTU and MRU"
default 1500
help
This options sets MTU and MRU for PPP link.
config NET_PPP_UART_BUF_LEN
int "Buffer length when reading from UART"
default 8

View file

@ -576,6 +576,20 @@ static int ppp_send(const struct device *dev, struct net_pkt *pkt)
protocol = htons(PPP_IP);
} else if (net_pkt_family(pkt) == AF_INET6) {
protocol = htons(PPP_IPV6);
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
net_pkt_family(pkt) == AF_PACKET) {
char type = (NET_IPV6_HDR(pkt)->vtc & 0xf0);
switch (type) {
case 0x60:
protocol = htons(PPP_IPV6);
break;
case 0x40:
protocol = htons(PPP_IP);
break;
default:
return -EPROTONOSUPPORT;
}
} else {
return -EPROTONOSUPPORT;
}

View file

@ -25,7 +25,7 @@ extern "C" {
*/
/** PPP maximum receive unit (MRU) */
#define PPP_MRU 1500
#define PPP_MRU CONFIG_NET_PPP_MTU_MRU
/** PPP maximum transfer unit (MTU) */
#define PPP_MTU PPP_MRU
@ -350,6 +350,10 @@ struct lcp_options {
uint16_t auth_proto;
};
#if defined(CONFIG_NET_L2_PPP_OPTION_MRU)
#define LCP_NUM_MY_OPTIONS 1
#endif
struct ipcp_options {
/** IPv4 address */
struct in_addr address;
@ -400,6 +404,9 @@ struct ppp_context {
/** Magic-Number value */
uint32_t magic;
#if defined(CONFIG_NET_L2_PPP_OPTION_MRU)
struct ppp_my_option_data my_options_data[LCP_NUM_MY_OPTIONS];
#endif
} lcp;
#if defined(CONFIG_NET_IPV4)

View file

@ -63,6 +63,21 @@ config NET_L2_PPP_PAP
help
Enable support for PAP authentication protocol.
config NET_L2_PPP_OPTION_MRU
bool "LCP MRU option support"
help
Enable support for LCP MRU option.
config NET_L2_PPP_OPTION_SERVE_IP
bool "Serve IP address to peer"
help
Enable support for serving IP address to PPP peer.
config NET_L2_PPP_OPTION_SERVE_DNS
bool "Serve DNS addresses to peer"
help
Enable support for serving DNS addresses to PPP peer.
module = NET_L2_PPP
module-dep = NET_LOG
module-str = Log level for ppp L2 layer

View file

@ -147,6 +147,32 @@ struct ipcp_peer_option_data {
struct in_addr addr;
};
#if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_DNS)
static int ipcp_dns_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
void *user_data)
{
struct ipcp_peer_option_data *data = user_data;
int ret;
ret = net_pkt_read(pkt, &data->addr, sizeof(data->addr));
if (ret < 0) {
/* Should not happen, is the pkt corrupt? */
return -EMSGSIZE;
}
/* Request is zeros? Give our dns address in ConfNak */
if (data->addr.s_addr == INADDR_ANY) {
NET_DBG("[IPCP] zeroes rcvd as %s addr, sending NAK with our %s addr",
"DNS", "DNS");
return -EINVAL;
}
data->addr_present = true;
return 0;
}
#endif
static int ipcp_ip_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
void *user_data)
{
@ -159,6 +185,14 @@ static int ipcp_ip_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
return -EMSGSIZE;
}
#if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_IP)
/* Request is zeros? Give our IP address in ConfNak */
if (data->addr.s_addr == INADDR_ANY) {
NET_DBG("[IPCP] zeroes rcvd as %s addr, sending NAK with our %s addr",
"IP", "IP");
return -EINVAL;
}
#endif
if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
char dst[INET_ADDRSTRLEN];
char *addr_str;
@ -175,8 +209,61 @@ static int ipcp_ip_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
return 0;
}
#if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_IP)
static int ipcp_server_nak_ip_address(struct ppp_fsm *fsm,
struct net_pkt *ret_pkt, void *user_data)
{
struct ppp_context *ctx =
CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_IP_ADDRESS);
ipcp_add_ip_address(ctx, ret_pkt);
return 0;
}
#endif
#if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_DNS)
static int ipcp_server_nak_dns1_address(struct ppp_fsm *fsm,
struct net_pkt *ret_pkt,
void *user_data)
{
struct ppp_context *ctx =
CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_DNS1);
ipcp_add_dns1(ctx, ret_pkt);
return 0;
}
static int ipcp_server_nak_dns2_address(struct ppp_fsm *fsm,
struct net_pkt *ret_pkt,
void *user_data)
{
struct ppp_context *ctx =
CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_DNS2);
ipcp_add_dns2(ctx, ret_pkt);
return 0;
}
#endif
static const struct ppp_peer_option_info ipcp_peer_options[] = {
#if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_IP)
PPP_PEER_OPTION(IPCP_OPTION_IP_ADDRESS, ipcp_ip_address_parse,
ipcp_server_nak_ip_address),
#else
PPP_PEER_OPTION(IPCP_OPTION_IP_ADDRESS, ipcp_ip_address_parse, NULL),
#endif
#if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_DNS)
PPP_PEER_OPTION(IPCP_OPTION_DNS1, ipcp_dns_address_parse,
ipcp_server_nak_dns1_address),
PPP_PEER_OPTION(IPCP_OPTION_DNS2, ipcp_dns_address_parse,
ipcp_server_nak_dns2_address),
#endif
};
static int ipcp_config_info_req(struct ppp_fsm *fsm,
@ -354,7 +441,6 @@ static void ipcp_down(struct ppp_fsm *fsm)
(void)net_if_ipv4_addr_rm(
ctx->iface, &ctx->ipcp.my_options.address);
}
memset(&ctx->ipcp.my_options.address, 0,
sizeof(ctx->ipcp.my_options.address));
memset(&ctx->ipcp.my_options.dns1_address, 0,

View file

@ -203,6 +203,95 @@ static void lcp_finished(struct ppp_fsm *fsm)
ppp_link_terminated(ctx);
}
#if defined(CONFIG_NET_L2_PPP_OPTION_MRU)
#define MRU_OPTION_LEN 4
static int lcp_add_mru(struct ppp_context *ctx, struct net_pkt *pkt)
{
net_pkt_write_u8(pkt, MRU_OPTION_LEN);
return net_pkt_write_be16(pkt, ctx->lcp.my_options.mru);
}
static int lcp_ack_mru(struct ppp_context *ctx, struct net_pkt *pkt,
uint8_t oplen)
{
int ret;
uint16_t mru;
/* Handle ACK : */
if (oplen != sizeof(mru)) {
return -EINVAL;
}
ret = net_pkt_read(pkt, &mru, sizeof(mru));
if (ret) {
return ret;
}
if (mru != ctx->lcp.my_options.mru) {
/* Didn't acked our MRU: */
return -EINVAL;
}
return 0;
}
static int lcp_nak_mru(struct ppp_context *ctx, struct net_pkt *pkt,
uint8_t oplen)
{
int ret;
uint16_t mru;
/* Handle NAK: accept only smaller/equal than ours */
if (oplen != sizeof(mru)) {
return -EINVAL;
}
ret = net_pkt_read(pkt, &mru, sizeof(mru));
if (ret) {
return ret;
}
if (mru <= ctx->lcp.my_options.mru) {
/* OK, reset the MRU also in our side: */
ctx->lcp.my_options.mru = mru;
} else {
return -EINVAL;
}
return 0;
}
static const struct ppp_my_option_info lcp_my_options[] = {
PPP_MY_OPTION(LCP_OPTION_MRU, lcp_add_mru, lcp_ack_mru, lcp_nak_mru),
};
BUILD_ASSERT(ARRAY_SIZE(lcp_my_options) == LCP_NUM_MY_OPTIONS);
static struct net_pkt *lcp_config_info_add(struct ppp_fsm *fsm)
{
return ppp_my_options_add(fsm, MRU_OPTION_LEN);
}
static int lcp_config_info_nack(struct ppp_fsm *fsm, struct net_pkt *pkt,
uint16_t length, bool rejected)
{
struct ppp_context *ctx =
CONTAINER_OF(fsm, struct ppp_context, lcp.fsm);
int ret;
ret = ppp_my_options_parse_conf_nak(fsm, pkt, length);
if (ret) {
return ret;
}
if (!ctx->lcp.my_options.mru) {
return -EINVAL;
}
return 0;
}
#endif
static void lcp_init(struct ppp_context *ctx)
{
NET_DBG("proto %s (0x%04x) fsm %p", ppp_proto2str(PPP_LCP), PPP_LCP,
@ -214,6 +303,18 @@ static void lcp_init(struct ppp_context *ctx)
ppp_fsm_name_set(&ctx->lcp.fsm, ppp_proto2str(PPP_LCP));
#if defined(CONFIG_NET_L2_PPP_OPTION_MRU)
ctx->lcp.my_options.mru = PPP_MRU;
ctx->lcp.fsm.my_options.info = lcp_my_options;
ctx->lcp.fsm.my_options.data = ctx->lcp.my_options_data;
ctx->lcp.fsm.my_options.count = ARRAY_SIZE(lcp_my_options);
ctx->lcp.fsm.cb.config_info_add = lcp_config_info_add;
ctx->lcp.fsm.cb.config_info_req = lcp_config_info_req;
ctx->lcp.fsm.cb.config_info_nack = lcp_config_info_nack;
ctx->lcp.fsm.cb.config_info_rej = ppp_my_options_parse_conf_rej;
#endif
ctx->lcp.fsm.cb.up = lcp_up;
ctx->lcp.fsm.cb.down = lcp_down;
ctx->lcp.fsm.cb.starting = lcp_starting;