Skip to content

Commit 79bd842

Browse files
committed
Fix DHCPv6 options serialization to prevent extra bytes in replies
In the `generate_reply_options` function, fixed an issue where DHCPv6 reply packets contained extra unintended bytes at the end. The problem was due to the `options` pointer not being incremented after copying the `opt_rapid` and `boot_file_url` options into the packet buffer. Changes made: - After copying `opt_rapid`, the `options` pointer is now incremented by `reply_options.opt_rapid_len`. - After copying `boot_file_url`, the `options` pointer is now incremented by `reply_options.opt_boot_file_len`. These changes ensure that all DHCPv6 options are correctly serialized in the packet buffer without overlaps or gaps. By properly advancing the `options` pointer, we prevent unintended data from being included at the end of the packet, eliminating the extra bytes that were being sent. This fix addresses the issue where clients were receiving malformed DHCPv6 packets due to the extra bytes, which could lead to communication errors or unexpected behavior.
1 parent a6d0032 commit 79bd842

File tree

1 file changed

+56
-52
lines changed

1 file changed

+56
-52
lines changed

src/nodes/dhcpv6_node.c

Lines changed: 56 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -210,58 +210,62 @@ static __rte_always_inline int strip_options(struct rte_mbuf *m, int options_len
210210
/** @return size of generated options or error */
211211
static int generate_reply_options(struct rte_mbuf *m, uint8_t *options, int options_len)
212212
{
213-
int reply_options_len;
214-
struct dhcpv6_opt_server_id_ll opt_sid;
215-
struct dhcpv6_opt_dns_servers dns_opt;
216-
struct dp_dhcpv6_reply_options reply_options = {0}; // this makes *_len fields 0, needed later
217-
const struct dp_conf_dhcp_dns *dhcpv6_dns = dp_conf_get_dhcpv6_dns();
218-
219-
if (DP_FAILED(parse_options(m, options, options_len, &reply_options))) {
220-
DPS_LOG_WARNING("Invalid DHCPv6 options received");
221-
return DP_ERROR;
222-
}
223-
224-
dns_opt.opt_code = htons(DHCPV6_OPT_DNS);
225-
dns_opt.opt_len = htons(dhcpv6_dns->len);
226-
227-
opt_sid = opt_sid_template;
228-
rte_ether_addr_copy(&rte_pktmbuf_mtod(m, struct rte_ether_hdr *)->dst_addr, &opt_sid.id.mac);
229-
230-
reply_options_len = (int)sizeof(opt_sid) + reply_options.opt_cid_len + reply_options.opt_iana_len + reply_options.opt_rapid_len;
231-
reply_options_len += (int)(sizeof(dns_opt.opt_code) + sizeof(dns_opt.opt_len) + ntohs(dns_opt.opt_len));
232-
233-
if (reply_options.pxe_mode != DP_PXE_MODE_NONE)
234-
reply_options_len += reply_options.opt_boot_file_len;
235-
236-
if (DP_FAILED(resize_packet(m, reply_options_len - options_len)))
237-
return DP_ERROR;
238-
239-
// had to use memcpy() here, because GCC's array-bounds check fails for rte_memcpy (using XMM optimization)
240-
memcpy(options, &opt_sid, sizeof(opt_sid));
241-
options += sizeof(opt_sid);
242-
if (reply_options.opt_cid_len) {
243-
memcpy(options, (void *)&reply_options.opt_cid, reply_options.opt_cid_len);
244-
options += reply_options.opt_cid_len;
245-
}
246-
if (reply_options.opt_iana_len) {
247-
memcpy(options, (void *)&reply_options.opt_iana, reply_options.opt_iana_len);
248-
options += reply_options.opt_iana_len;
249-
}
250-
if (reply_options.opt_rapid_len)
251-
memcpy(options, &reply_options.opt_rapid, reply_options.opt_rapid_len);
252-
253-
// Add DNS server option
254-
memcpy(options, &dns_opt.opt_code, sizeof(dns_opt.opt_code));
255-
options += sizeof(dns_opt.opt_code);
256-
memcpy(options, &dns_opt.opt_len, sizeof(dns_opt.opt_len));
257-
options += sizeof(dns_opt.opt_len);
258-
memcpy(options, dhcpv6_dns->array, dhcpv6_dns->len);
259-
options += dhcpv6_dns->len;
260-
261-
if (reply_options.pxe_mode != DP_PXE_MODE_NONE)
262-
memcpy(options, &reply_options.boot_file_url, reply_options.opt_boot_file_len);
263-
264-
return reply_options_len;
213+
int reply_options_len;
214+
struct dhcpv6_opt_server_id_ll opt_sid;
215+
struct dhcpv6_opt_dns_servers dns_opt;
216+
struct dp_dhcpv6_reply_options reply_options = {0}; // this makes *_len fields 0, needed later
217+
const struct dp_conf_dhcp_dns *dhcpv6_dns = dp_conf_get_dhcpv6_dns();
218+
219+
if (DP_FAILED(parse_options(m, options, options_len, &reply_options))) {
220+
DPS_LOG_WARNING("Invalid DHCPv6 options received");
221+
return DP_ERROR;
222+
}
223+
224+
dns_opt.opt_code = htons(DHCPV6_OPT_DNS);
225+
dns_opt.opt_len = htons(dhcpv6_dns->len);
226+
227+
opt_sid = opt_sid_template;
228+
rte_ether_addr_copy(&rte_pktmbuf_mtod(m, struct rte_ether_hdr *)->dst_addr, &opt_sid.id.mac);
229+
230+
reply_options_len = (int)sizeof(opt_sid) + reply_options.opt_cid_len + reply_options.opt_iana_len + reply_options.opt_rapid_len;
231+
reply_options_len += (int)(sizeof(dns_opt.opt_code) + sizeof(dns_opt.opt_len) + ntohs(dns_opt.opt_len));
232+
233+
if (reply_options.pxe_mode != DP_PXE_MODE_NONE)
234+
reply_options_len += reply_options.opt_boot_file_len;
235+
236+
if (DP_FAILED(resize_packet(m, reply_options_len - options_len)))
237+
return DP_ERROR;
238+
239+
// had to use memcpy() here, because GCC's array-bounds check fails for rte_memcpy (using XMM optimization)
240+
memcpy(options, &opt_sid, sizeof(opt_sid));
241+
options += sizeof(opt_sid);
242+
if (reply_options.opt_cid_len) {
243+
memcpy(options, (void *)&reply_options.opt_cid, reply_options.opt_cid_len);
244+
options += reply_options.opt_cid_len;
245+
}
246+
if (reply_options.opt_iana_len) {
247+
memcpy(options, (void *)&reply_options.opt_iana, reply_options.opt_iana_len);
248+
options += reply_options.opt_iana_len;
249+
}
250+
if (reply_options.opt_rapid_len) {
251+
memcpy(options, &reply_options.opt_rapid, reply_options.opt_rapid_len);
252+
options += reply_options.opt_rapid_len; // **Added this line**
253+
}
254+
255+
// Add DNS server option
256+
memcpy(options, &dns_opt.opt_code, sizeof(dns_opt.opt_code));
257+
options += sizeof(dns_opt.opt_code);
258+
memcpy(options, &dns_opt.opt_len, sizeof(dns_opt.opt_len));
259+
options += sizeof(dns_opt.opt_len);
260+
memcpy(options, dhcpv6_dns->array, dhcpv6_dns->len);
261+
options += dhcpv6_dns->len;
262+
263+
if (reply_options.pxe_mode != DP_PXE_MODE_NONE) {
264+
memcpy(options, &reply_options.boot_file_url, reply_options.opt_boot_file_len);
265+
options += reply_options.opt_boot_file_len; // **Added this line**
266+
}
267+
268+
return reply_options_len;
265269
}
266270

267271
static __rte_always_inline rte_edge_t get_next_index(struct rte_node *node, struct rte_mbuf *m)

0 commit comments

Comments
 (0)