net: l2: ppp: use net_pkt API for replying to Configure-Req

Use net_pkt instead of net_buf API for replying to Configure-Req. We use
the fact that for now we reply with either Configure-Ack or
Configure-Rej only. In both cases we can allocate net_pkt ahead, because
we know its maximum length (which is equal to length of received
Configure-Req packet).

Make also an improvement in generic FSM code and reply with
Configure-Rej to all Configure-Req for which there is no config_info_req
callback set. Use that to drop LCP specific Conf-Req handling code,
because there is no option properly supported there yet.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
This commit is contained in:
Marcin Niestroj 2020-07-27 16:32:19 +02:00 committed by Carles Cufí
parent b091181fa5
commit 50b2cafc42
5 changed files with 71 additions and 276 deletions

View File

@ -241,7 +241,7 @@ struct ppp_fsm {
int (*config_info_req)(struct ppp_fsm *fsm,
struct net_pkt *pkt,
uint16_t length,
struct net_buf **buf);
struct net_pkt *ret_pkt);
/** Reject Configuration Information */
int (*config_info_rej)(struct ppp_fsm *fsm,

View File

@ -351,7 +351,7 @@ int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface,
uint16_t protocol = 0;
size_t len = 0;
struct ppp_packet ppp;
struct net_pkt *pkt;
struct net_pkt *pkt = NULL;
int ret;
if (!iface) {
@ -390,6 +390,8 @@ int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface,
case PPP_CONFIGURE_ACK:
case PPP_CONFIGURE_NACK:
case PPP_CONFIGURE_REJ:
pkt = data;
/* FALLTHROUGH */
case PPP_CONFIGURE_REQ:
/* 2 + 1 + 1 (configure-[req|ack|nack|rej]) +
* data_len (options)
@ -431,11 +433,25 @@ int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface,
ppp.id = id;
ppp.length = htons(len);
pkt = net_pkt_alloc_with_buffer(iface,
sizeof(uint16_t) + len,
AF_UNSPEC, 0, BUF_ALLOC_TIMEOUT);
if (!pkt) {
goto out_of_mem;
pkt = net_pkt_alloc_with_buffer(iface,
sizeof(uint16_t) + len,
AF_UNSPEC, 0,
BUF_ALLOC_TIMEOUT);
if (!pkt) {
goto out_of_mem;
}
} else {
struct net_buf *buf;
buf = net_pkt_get_reserve_tx_data(BUF_ALLOC_TIMEOUT);
if (!buf) {
LOG_ERR("failed to allocate buffer");
goto out_of_mem;
}
net_pkt_frag_insert(pkt, buf);
net_pkt_cursor_init(pkt);
}
ret = net_pkt_write_be16(pkt, protocol);
@ -483,8 +499,7 @@ int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface,
}
} else if (type == PPP_ECHO_REPLY) {
net_pkt_copy(pkt, req_pkt, len);
} else if (type == PPP_CONFIGURE_ACK || type == PPP_CONFIGURE_REQ ||
type == PPP_CONFIGURE_REJ || type == PPP_CONFIGURE_NACK) {
} else if (type == PPP_CONFIGURE_REQ) {
/* add options */
if (data) {
net_buf_frag_add(pkt->buffer, data);
@ -533,7 +548,7 @@ static enum net_verdict fsm_recv_configure_req(struct ppp_fsm *fsm,
struct net_pkt *pkt,
uint16_t remaining_len)
{
struct net_buf *buf = NULL;
struct net_pkt *out = NULL;
int len = 0;
enum ppp_packet_type code;
@ -578,12 +593,23 @@ static enum net_verdict fsm_recv_configure_req(struct ppp_fsm *fsm,
return NET_DROP;
}
out = net_pkt_alloc_with_buffer(net_pkt_iface(pkt),
sizeof(uint16_t) + sizeof(uint16_t) +
sizeof(uint8_t) + sizeof(uint8_t) +
remaining_len,
AF_UNSPEC, 0, BUF_ALLOC_TIMEOUT);
if (!out) {
return NET_DROP;
}
net_pkt_cursor_init(out);
if (fsm->cb.config_info_req) {
int ret;
ret = fsm->cb.config_info_req(fsm, pkt, remaining_len, &buf);
ret = fsm->cb.config_info_req(fsm, pkt, remaining_len, out);
if (ret < 0) {
return NET_DROP;
goto unref_out_pkt;
}
if (fsm->nack_loops >= MAX_NACK_LOOPS &&
@ -592,13 +618,12 @@ static enum net_verdict fsm_recv_configure_req(struct ppp_fsm *fsm,
}
code = ret;
len = net_buf_frags_len(buf);
len = net_pkt_get_len(out);
} else if (remaining_len) {
/* If there are any options at this point, then reject.
* TODO: construct the NACKed options buf
*/
code = PPP_CONFIGURE_REJ;
net_pkt_copy(out, pkt, remaining_len);
len = remaining_len;
} else {
code = PPP_CONFIGURE_ACK;
}
@ -607,7 +632,7 @@ static enum net_verdict fsm_recv_configure_req(struct ppp_fsm *fsm,
fsm->name, fsm, ppp_pkt_type2str(code), code, id,
ppp_state_str(fsm->state), fsm->state);
(void)ppp_send_pkt(fsm, NULL, code, id, buf, len);
(void)ppp_send_pkt(fsm, NULL, code, id, out, len);
if (code == PPP_CONFIGURE_ACK) {
if (fsm->state == PPP_ACK_RECEIVED) {
@ -634,6 +659,11 @@ static enum net_verdict fsm_recv_configure_req(struct ppp_fsm *fsm,
}
return NET_OK;
unref_out_pkt:
net_pkt_unref(out);
return NET_DROP;
}
static enum net_verdict fsm_recv_configure_ack(struct ppp_fsm *fsm, uint8_t id,

View File

@ -100,10 +100,9 @@ out_of_mem:
static int ipcp_config_info_req(struct ppp_fsm *fsm,
struct net_pkt *pkt,
uint16_t length,
struct net_buf **ret_buf)
struct net_pkt *ret_pkt)
{
int nack_idx = 0, address_option_idx = -1;
struct net_buf *buf = NULL;
struct ppp_option_pkt options[MAX_IPCP_OPTIONS];
struct ppp_option_pkt nack_options[MAX_IPCP_OPTIONS];
enum ppp_packet_type code;
@ -152,43 +151,19 @@ static int ipcp_config_info_req(struct ppp_fsm *fsm,
}
if (nack_idx > 0) {
struct net_buf *nack_buf;
code = PPP_CONFIGURE_REJ;
/* Create net_buf containing options that are not accepted */
/* Fill ret_pkt with options that are not accepted */
for (i = 0; i < MIN(nack_idx, ARRAY_SIZE(nack_options)); i++) {
bool added;
nack_buf = ppp_get_net_buf(buf, nack_options[i].len);
if (!nack_buf) {
goto bail_out;
}
if (!buf) {
buf = nack_buf;
}
added = append_to_buf(nack_buf,
&nack_options[i].type.ipcp, 1);
if (!added) {
goto bail_out;
}
added = append_to_buf(nack_buf, &nack_options[i].len,
1);
if (!added) {
goto bail_out;
}
net_pkt_write_u8(ret_pkt, nack_options[i].type.ipcp);
net_pkt_write_u8(ret_pkt, nack_options[i].len);
/* If there is some data, copy it to result buf */
if (nack_options[i].value.pos) {
added = append_to_buf(nack_buf,
nack_options[i].value.pos,
nack_options[i].len - 1 - 1);
if (!added) {
goto bail_out;
}
net_pkt_cursor_restore(pkt,
&nack_options[i].value);
net_pkt_copy(ret_pkt, pkt,
nack_options[i].len - 1 - 1);
}
}
} else {
@ -232,9 +207,6 @@ static int ipcp_config_info_req(struct ppp_fsm *fsm,
}
if (addr.s_addr) {
bool added;
uint8_t val;
/* The address is the remote address, we then need
* to figure out what our address should be.
*
@ -242,43 +214,15 @@ static int ipcp_config_info_req(struct ppp_fsm *fsm,
* - check that the IP address can be accepted
*/
buf = ppp_get_net_buf(NULL, IP_ADDRESS_OPTION_LEN);
if (!buf) {
goto bail_out;
}
net_pkt_write_u8(ret_pkt, IPCP_OPTION_IP_ADDRESS);
net_pkt_write_u8(ret_pkt, IP_ADDRESS_OPTION_LEN);
val = IPCP_OPTION_IP_ADDRESS;
added = append_to_buf(buf, &val, sizeof(val));
if (!added) {
goto bail_out;
}
val = IP_ADDRESS_OPTION_LEN;
added = append_to_buf(buf, &val, sizeof(val));
if (!added) {
goto bail_out;
}
added = append_to_buf(buf, (uint8_t *)&addr.s_addr,
sizeof(addr.s_addr));
if (!added) {
goto bail_out;
}
net_pkt_write(ret_pkt, &addr.s_addr,
sizeof(addr.s_addr));
}
}
if (buf) {
*ret_buf = buf;
}
return code;
bail_out:
if (buf) {
net_buf_unref(buf);
}
return -ENOMEM;
}
static void ipcp_set_dns_servers(struct ppp_fsm *fsm)

View File

@ -90,10 +90,9 @@ out_of_mem:
static int ipv6cp_config_info_req(struct ppp_fsm *fsm,
struct net_pkt *pkt,
uint16_t length,
struct net_buf **ret_buf)
struct net_pkt *ret_pkt)
{
int nack_idx = 0, iface_id_option_idx = -1;
struct net_buf *buf = NULL;
struct ppp_option_pkt options[MAX_IPV6CP_OPTIONS];
struct ppp_option_pkt nack_options[MAX_IPV6CP_OPTIONS];
enum ppp_packet_type code;
@ -143,52 +142,24 @@ static int ipv6cp_config_info_req(struct ppp_fsm *fsm,
}
if (nack_idx > 0) {
struct net_buf *nack_buf;
code = PPP_CONFIGURE_REJ;
/* Once rejected count logic is in, it will be possible
* to set this code to PPP_CONFIGURE_REJ. */
code = PPP_CONFIGURE_NACK;
/* Create net_buf containing options that are not accepted */
/* Fill ret_pkt with options that are not accepted */
for (i = 0; i < MIN(nack_idx, ARRAY_SIZE(nack_options)); i++) {
bool added;
nack_buf = ppp_get_net_buf(buf, nack_options[i].len);
if (!nack_buf) {
goto bail_out;
}
if (!buf) {
buf = nack_buf;
}
added = append_to_buf(nack_buf,
&nack_options[i].type.ipv6cp, 1);
if (!added) {
goto bail_out;
}
added = append_to_buf(nack_buf, &nack_options[i].len,
1);
if (!added) {
goto bail_out;
}
net_pkt_write_u8(ret_pkt, nack_options[i].type.ipv6cp);
net_pkt_write_u8(ret_pkt, nack_options[i].len);
/* If there is some data, copy it to result buf */
if (nack_options[i].value.pos) {
added = append_to_buf(nack_buf,
nack_options[i].value.pos,
nack_options[i].len - 1 - 1);
if (!added) {
goto bail_out;
}
net_pkt_cursor_restore(pkt,
&nack_options[i].value);
net_pkt_copy(ret_pkt, pkt,
nack_options[i].len - 1 - 1);
}
}
} else {
uint8_t iface_id[PPP_INTERFACE_IDENTIFIER_LEN];
struct ppp_context *ctx;
bool added;
uint8_t val;
int ret;
ctx = CONTAINER_OF(fsm, struct ppp_context, ipv6cp.fsm);
@ -224,41 +195,13 @@ static int ipv6cp_config_info_req(struct ppp_fsm *fsm,
/* TODO: check whether iid is empty and create one if so */
buf = ppp_get_net_buf(NULL, INTERFACE_IDENTIFIER_OPTION_LEN);
if (!buf) {
goto bail_out;
}
net_pkt_write_u8(ret_pkt, IPV6CP_OPTION_INTERFACE_IDENTIFIER);
net_pkt_write_u8(ret_pkt, INTERFACE_IDENTIFIER_OPTION_LEN);
val = IPV6CP_OPTION_INTERFACE_IDENTIFIER;
added = append_to_buf(buf, &val, sizeof(val));
if (!added) {
goto bail_out;
}
val = INTERFACE_IDENTIFIER_OPTION_LEN;
added = append_to_buf(buf, &val, sizeof(val));
if (!added) {
goto bail_out;
}
added = append_to_buf(buf, iface_id, sizeof(iface_id));
if (!added) {
goto bail_out;
}
}
if (buf) {
*ret_buf = buf;
net_pkt_write(ret_pkt, iface_id, sizeof(iface_id));
}
return code;
bail_out:
if (buf) {
net_buf_unref(buf);
}
return -ENOMEM;
}
static int ipv6cp_config_info_ack(struct ppp_fsm *fsm,

View File

@ -57,127 +57,6 @@ static enum net_verdict lcp_handle(struct ppp_context *ctx,
return ppp_fsm_input(&ctx->lcp.fsm, PPP_LCP, pkt);
}
static bool append_to_buf(struct net_buf *buf, uint8_t *data, uint8_t data_len)
{
if (data_len > net_buf_tailroom(buf)) {
return false;
}
/* FIXME: use net_pkt api so that we can handle a case where data
* might split to two net_buf's
*/
net_buf_add_mem(buf, data, data_len);
return true;
}
static int lcp_config_info_req(struct ppp_fsm *fsm,
struct net_pkt *pkt,
uint16_t length,
struct net_buf **buf)
{
struct ppp_option_pkt options[MAX_LCP_OPTIONS];
struct ppp_option_pkt nack_options[MAX_LCP_OPTIONS];
struct net_buf *nack = NULL;
enum ppp_packet_type code;
int i, nack_idx = 0;
int ret;
memset(options, 0, sizeof(options));
memset(nack_options, 0, sizeof(nack_options));
ret = ppp_parse_options(fsm, pkt, length, options, ARRAY_SIZE(options));
if (ret < 0) {
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(options); i++) {
if (options[i].type.lcp != LCP_OPTION_RESERVED) {
NET_DBG("[%s/%p] %s option %s (%d) len %d",
fsm->name, fsm, "Check",
ppp_option2str(PPP_LCP, options[i].type.lcp),
options[i].type.lcp, options[i].len);
}
switch (options[i].type.lcp) {
case LCP_OPTION_RESERVED:
continue;
default:
nack_options[nack_idx].type.lcp = options[i].type.lcp;
nack_options[nack_idx].len = options[i].len;
if (options[i].len > 2) {
memcpy(&nack_options[nack_idx].value,
&options[i].value,
sizeof(nack_options[nack_idx].value));
}
nack_idx++;
break;
}
}
if (nack_idx > 0) {
struct net_buf *nack_buf;
code = PPP_CONFIGURE_REJ;
/* Create net_buf containing options that are not accepted */
for (i = 0; i < MIN(nack_idx, ARRAY_SIZE(nack_options)); i++) {
bool added;
nack_buf = ppp_get_net_buf(nack, nack_options[i].len);
if (!nack_buf) {
goto out_of_mem;
}
if (!nack) {
nack = nack_buf;
}
added = append_to_buf(nack_buf,
&nack_options[i].type.lcp, 1);
if (!added) {
goto out_of_mem;
}
added = append_to_buf(nack_buf, &nack_options[i].len,
1);
if (!added) {
goto out_of_mem;
}
/* If there is some data, copy it to result buf */
if (nack_options[i].value.pos) {
added = append_to_buf(nack_buf,
nack_options[i].value.pos,
nack_options[i].len - 1 - 1);
if (!added) {
goto out_of_mem;
}
}
continue;
out_of_mem:
if (nack) {
net_buf_unref(nack);
}
return -ENOMEM;
}
} else {
code = PPP_CONFIGURE_ACK;
}
if (nack) {
*buf = nack;
}
return code;
}
static void lcp_lower_down(struct ppp_context *ctx)
{
ppp_fsm_lower_down(&ctx->lcp.fsm);
@ -256,7 +135,6 @@ static void lcp_init(struct ppp_context *ctx)
ctx->lcp.fsm.cb.starting = lcp_starting;
ctx->lcp.fsm.cb.finished = lcp_finished;
ctx->lcp.fsm.cb.proto_extension = lcp_handle_ext;
ctx->lcp.fsm.cb.config_info_req = lcp_config_info_req;
}
PPP_PROTOCOL_REGISTER(LCP, PPP_LCP,