Commit d5f4ca3b authored by Seppo Takalo's avatar Seppo Takalo Committed by Anas Nashif
Browse files

net: ppp: Allow peer-options to be rejected

There are cases, for example when peer is requesting two DNS
addresses, but we can only give one, we should reject the secondary
DNS request first, before sending NAK to acceptable options.

Option parser can reject a parameter by returning -ENOTSUP and when
it wants to NAK the parameter, it returns -EINVAL.

On RFC 1661:
Configure-Reject
  If some Configuration Options received in a Configure-Request are
  not recognizable or are not acceptable for negotiation (as
  configured by a network administrator), then the implementation
  MUST transmit a Configure-Reject.

Configure-Nak
  If every instance of the received Configuration Options is
  recognizable, but some values are not acceptable, then the
  implementation MUST transmit a Configure-Nak.

So as stated by RFC, we should start the negotiation by rejecting all
parameters that we cannot configure. I added an example of rejecting
DNS requests, if we don't have those.

Signed-off-by: default avatarSeppo Takalo <seppo.takalo@nordicsemi.no>
parent 5a31f3d1
Loading
Loading
Loading
Loading
+33 −2
Changes for subsys/net/l2/ppp/ipcp.c: 33 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -228,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)
@@ -263,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
};
+29 −1
Changes for subsys/net/l2/ppp/options.c: 29 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -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);
@@ -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;
	}