Skip to content

net: ppp: ipcp: Improvements to DNS option negotiation #93181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/zephyr/net/ppp.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,11 @@ struct ppp_my_option_data {
uint32_t flags;
};

#if defined(CONFIG_NET_L2_PPP_OPTION_DNS_USE)
#define IPCP_NUM_MY_OPTIONS 3
#else
#define IPCP_NUM_MY_OPTIONS 1
#endif
#define IPV6CP_NUM_MY_OPTIONS 1

enum ppp_flags {
Expand Down
93 changes: 64 additions & 29 deletions subsys/net/l2/ppp/ipcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,6 @@ static int ipcp_add_ip_address(struct ppp_context *ctx, struct net_pkt *pkt)
return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.address);
}

static int ipcp_add_dns1(struct ppp_context *ctx, struct net_pkt *pkt)
{
return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.dns1_address);
}

static int ipcp_add_dns2(struct ppp_context *ctx, struct net_pkt *pkt)
{
return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.dns2_address);
}

static int ipcp_ack_check_address(struct net_pkt *pkt, size_t oplen,
struct in_addr *addr)
{
Expand Down Expand Up @@ -81,20 +71,6 @@ static int ipcp_ack_ip_address(struct ppp_context *ctx, struct net_pkt *pkt,
&ctx->ipcp.my_options.address);
}

static int ipcp_ack_dns1(struct ppp_context *ctx, struct net_pkt *pkt,
uint8_t oplen)
{
return ipcp_ack_check_address(pkt, oplen,
&ctx->ipcp.my_options.dns1_address);
}

static int ipcp_ack_dns2(struct ppp_context *ctx, struct net_pkt *pkt,
uint8_t oplen)
{
return ipcp_ack_check_address(pkt, oplen,
&ctx->ipcp.my_options.dns2_address);
}

static int ipcp_nak_override_address(struct net_pkt *pkt, size_t oplen,
struct in_addr *addr)
{
Expand All @@ -112,6 +88,31 @@ static int ipcp_nak_ip_address(struct ppp_context *ctx, struct net_pkt *pkt,
&ctx->ipcp.my_options.address);
}

#if defined(CONFIG_NET_L2_PPP_OPTION_DNS_USE)
static int ipcp_add_dns1(struct ppp_context *ctx, struct net_pkt *pkt)
{
return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.dns1_address);
}

static int ipcp_add_dns2(struct ppp_context *ctx, struct net_pkt *pkt)
{
return ipcp_add_address(ctx, pkt, &ctx->ipcp.my_options.dns2_address);
}

static int ipcp_ack_dns1(struct ppp_context *ctx, struct net_pkt *pkt,
uint8_t oplen)
{
return ipcp_ack_check_address(pkt, oplen,
&ctx->ipcp.my_options.dns1_address);
}

static int ipcp_ack_dns2(struct ppp_context *ctx, struct net_pkt *pkt,
uint8_t oplen)
{
return ipcp_ack_check_address(pkt, oplen,
&ctx->ipcp.my_options.dns2_address);
}

static int ipcp_nak_dns1(struct ppp_context *ctx, struct net_pkt *pkt,
uint8_t oplen)
{
Expand All @@ -125,21 +126,24 @@ static int ipcp_nak_dns2(struct ppp_context *ctx, struct net_pkt *pkt,
return ipcp_nak_override_address(pkt, oplen,
&ctx->ipcp.my_options.dns2_address);
}
#endif /* CONFIG_NET_L2_PPP_OPTION_DNS_USE */

static const struct ppp_my_option_info ipcp_my_options[] = {
PPP_MY_OPTION(IPCP_OPTION_IP_ADDRESS, ipcp_add_ip_address,
ipcp_ack_ip_address, ipcp_nak_ip_address),
#if defined(CONFIG_NET_L2_PPP_OPTION_DNS_USE)
PPP_MY_OPTION(IPCP_OPTION_DNS1, ipcp_add_dns1,
ipcp_ack_dns1, ipcp_nak_dns1),
PPP_MY_OPTION(IPCP_OPTION_DNS2, ipcp_add_dns2,
ipcp_ack_dns2, ipcp_nak_dns2),
#endif
};

BUILD_ASSERT(ARRAY_SIZE(ipcp_my_options) == IPCP_NUM_MY_OPTIONS);

static struct net_pkt *ipcp_config_info_add(struct ppp_fsm *fsm)
{
return ppp_my_options_add(fsm, 3 * IP_ADDRESS_OPTION_LEN);
return ppp_my_options_add(fsm, IPCP_NUM_MY_OPTIONS * IP_ADDRESS_OPTION_LEN);
}

struct ipcp_peer_option_data {
Expand Down Expand Up @@ -224,6 +228,37 @@ static int ipcp_server_nak_ip_address(struct ppp_fsm *fsm,
#endif

#if defined(CONFIG_NET_L2_PPP_OPTION_SERVE_DNS)

static int ipcp_dns1_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
void *user_data)
{
struct ppp_context *ctx =
CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
int ret;

ret = ipcp_dns_address_parse(fsm, pkt, user_data);

if (ret == -EINVAL && ctx->ipcp.peer_options.dns1_address.s_addr == INADDR_ANY) {
return -ENOTSUP;
}
return ret;
}

static int ipcp_dns2_address_parse(struct ppp_fsm *fsm, struct net_pkt *pkt,
void *user_data)
{
struct ppp_context *ctx =
CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
int ret;

ret = ipcp_dns_address_parse(fsm, pkt, user_data);

if (ret == -EINVAL && ctx->ipcp.peer_options.dns2_address.s_addr == INADDR_ANY) {
return -ENOTSUP;
}
return ret;
}

static int ipcp_server_nak_dns1_address(struct ppp_fsm *fsm,
struct net_pkt *ret_pkt,
void *user_data)
Expand All @@ -232,7 +267,7 @@ static int ipcp_server_nak_dns1_address(struct ppp_fsm *fsm,
CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);

(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_DNS1);
ipcp_add_dns1(ctx, ret_pkt);
(void)ipcp_add_address(ctx, ret_pkt, &ctx->ipcp.peer_options.dns1_address);

return 0;
}
Expand All @@ -245,7 +280,7 @@ static int ipcp_server_nak_dns2_address(struct ppp_fsm *fsm,
CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);

(void)net_pkt_write_u8(ret_pkt, IPCP_OPTION_DNS2);
ipcp_add_dns2(ctx, ret_pkt);
(void)ipcp_add_address(ctx, ret_pkt, &ctx->ipcp.peer_options.dns2_address);

return 0;
}
Expand All @@ -259,9 +294,9 @@ static const struct ppp_peer_option_info ipcp_peer_options[] = {
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,
PPP_PEER_OPTION(IPCP_OPTION_DNS1, ipcp_dns1_address_parse,
ipcp_server_nak_dns1_address),
PPP_PEER_OPTION(IPCP_OPTION_DNS2, ipcp_dns_address_parse,
PPP_PEER_OPTION(IPCP_OPTION_DNS2, ipcp_dns2_address_parse,
ipcp_server_nak_dns2_address),
#endif
};
Expand Down
30 changes: 29 additions & 1 deletion subsys/net/l2/ppp/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,38 @@ static int ppp_parse_option_conf_req_supported(struct net_pkt *pkt,
{
struct ppp_parse_option_conf_req_data *parse_data = user_data;
struct ppp_fsm *fsm = parse_data->fsm;
struct net_pkt *ret_pkt = parse_data->ret_pkt;
struct net_pkt_cursor cursor;
const struct ppp_peer_option_info *option_info =
ppp_peer_option_info_get(parse_data->options_info,
parse_data->num_options_info,
code);
int ret;

net_pkt_cursor_backup(pkt, &cursor);
ret = option_info->parse(fsm, pkt, parse_data->user_data);
if (ret == -EINVAL) {
if (ret == -ENOTSUP) {
net_pkt_cursor_restore(pkt, &cursor);
parse_data->rej_count++;
if (parse_data->nack_count != 0) {
/* Remove any NACKed data, if we need to reject something first */
net_pkt_update_length(ret_pkt, 0);
net_pkt_cursor_init(ret_pkt);
parse_data->nack_count = 0;
}
net_pkt_write_u8(ret_pkt, code);
net_pkt_write_u8(ret_pkt, len + sizeof(code) + sizeof(len));
if (len > 0) {
net_pkt_copy(ret_pkt, pkt, len);
}
return 0;
} else if (ret == -EINVAL) {
if (parse_data->rej_count != 0) {
/* If we have already rejected some options, we
* cannot NACK anything in the same packet.
*/
return 0;
}
parse_data->nack_count++;
ret = option_info->nack(fsm, parse_data->ret_pkt,
parse_data->user_data);
Expand Down Expand Up @@ -202,6 +226,10 @@ int ppp_config_info_req(struct ppp_fsm *fsm,
return -EINVAL;
}

if (parse_data.rej_count) {
return PPP_CONFIGURE_REJ;
}

if (parse_data.nack_count) {
return PPP_CONFIGURE_NACK;
}
Expand Down