From 3d5d5732c28680fe39732ab63dd2ee1a2baad0ea Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Thu, 30 Mar 2023 19:23:58 +0000 Subject: [PATCH] A10NSP DHCPv6 and LDRA This commit adds support for DHCPv6 on A10NSP interfaces (#87). It also adds general support for DHCPv6 LDRA (#96 and #157). --- code/bngblaster/src/bbl_a10nsp.c | 142 ++++++++++++++++++ code/bngblaster/src/bbl_access.c | 6 - code/bngblaster/src/bbl_config.c | 10 ++ code/bngblaster/src/bbl_config.h | 1 + code/bngblaster/src/bbl_ctx.h | 1 + code/bngblaster/src/bbl_def.h | 8 + code/bngblaster/src/bbl_dhcpv6.c | 8 + code/bngblaster/src/bbl_protocols.c | 135 +++++++++++++---- code/bngblaster/src/bbl_protocols.h | 9 ++ code/bngblaster/src/bbl_tx.c | 33 ++-- docsrc/sources/configuration/dhcpv6.rst | 10 +- .../configuration/interfaces_access.rst | 3 + 12 files changed, 323 insertions(+), 43 deletions(-) diff --git a/code/bngblaster/src/bbl_a10nsp.c b/code/bngblaster/src/bbl_a10nsp.c index cb85725e..d54c676e 100644 --- a/code/bngblaster/src/bbl_a10nsp.c +++ b/code/bngblaster/src/bbl_a10nsp.c @@ -459,6 +459,122 @@ bbl_a10nsp_dhcp_handler(bbl_a10nsp_interface_s *interface, } } +static void +bbl_a10nsp_dhcpv6_handler(bbl_a10nsp_interface_s *interface, + bbl_session_s *session, + bbl_ethernet_header_s *eth) +{ + bbl_a10nsp_session_s *a10nsp_session = session->a10nsp_session; + bbl_ipv6_s *ipv6 = (bbl_ipv6_s*)eth->next; + bbl_udp_s *udp = (bbl_udp_s*)ipv6->next; + + bbl_dhcpv6_s *dhcpv6 = (bbl_dhcpv6_s*)udp->next; + bbl_dhcpv6_s *dhcpv6_outer = dhcpv6; + + if(dhcpv6->type == DHCPV6_MESSAGE_RELAY_FORW) { + if(!dhcpv6->relay_message) { + /* Invalid request. */ + return; + } + dhcpv6 = dhcpv6->relay_message; + dhcpv6_outer->type = DHCPV6_MESSAGE_RELAY_REPL; + } + + switch(dhcpv6->type) { + case DHCPV6_MESSAGE_SOLICIT: + if(dhcpv6->rapid) { + dhcpv6->type = DHCPV6_MESSAGE_REPLY; + } else { + dhcpv6->type = DHCPV6_MESSAGE_ADVERTISE; + } + break; + case DHCPV6_MESSAGE_REQUEST: + dhcpv6->type = DHCPV6_MESSAGE_REPLY; + break; + case DHCPV6_MESSAGE_RELEASE: + dhcpv6->type = DHCPV6_MESSAGE_REPLY; + break; + default: + return; + } + + if(dhcpv6_outer->access_line) { + if(dhcpv6_outer->access_line->aci) { + if(a10nsp_session->dhcpv6_aci) { + free(a10nsp_session->dhcpv6_aci); + } + a10nsp_session->dhcp_aci = strdup(dhcpv6_outer->access_line->aci); + } + if(dhcpv6_outer->access_line->ari) { + if(a10nsp_session->dhcpv6_ari) { + free(a10nsp_session->dhcpv6_ari); + } + a10nsp_session->dhcpv6_ari = strdup(dhcpv6_outer->access_line->ari); + } + dhcpv6_outer->access_line = NULL; + } + + ipv6->dst = ipv6->src; + ipv6->src = (void*)ipv6_link_local_address; + ipv6->ttl = 255; + udp->src = DHCPV6_UDP_SERVER; + udp->dst = DHCPV6_UDP_CLIENT; + + dhcpv6->server_duid = (void*)mock_dhcpv6_server_duid; + dhcpv6->server_duid_len = sizeof(mock_dhcpv6_server_duid); + dhcpv6->rapid = false; + dhcpv6->oro = false; + dhcpv6->dns1 = NULL; + dhcpv6->dns2 = NULL; + if(dhcpv6->ia_na_iaid) { + dhcpv6->ia_na_option_len = 0; + dhcpv6->ia_na_address = (void*)&mock_ipv6_ia_na; + dhcpv6->ia_na_t1 = 300; + dhcpv6->ia_na_t2 = 600; + dhcpv6->ia_na_preferred_lifetime = 900; + dhcpv6->ia_na_valid_lifetime = 1800; + } + if(dhcpv6->ia_pd_iaid) { + dhcpv6->ia_pd_option_len = 0; + dhcpv6->ia_pd_prefix = (void*)&mock_ipv6_ia_pd; + dhcpv6->ia_pd_t1 = 300; + dhcpv6->ia_pd_t2 = 600; + dhcpv6->ia_pd_preferred_lifetime = 900; + dhcpv6->ia_pd_valid_lifetime = 1800; + } + + if(bbl_txq_to_buffer(interface->txq, eth) == BBL_TXQ_OK) { + a10nsp_session->stats.packets_tx++; + } +} + +static void +bbl_a10nsp_icmpv6_handler(bbl_a10nsp_interface_s *interface, + bbl_session_s *session, + bbl_ethernet_header_s *eth) +{ + bbl_a10nsp_session_s *a10nsp_session = session->a10nsp_session; + bbl_ipv6_s *ipv6 = (bbl_ipv6_s*)eth->next; + bbl_icmpv6_s *icmpv6 = (bbl_icmpv6_s*)ipv6->next; + + switch(icmpv6->type) { + case IPV6_ICMPV6_ROUTER_SOLICITATION: + icmpv6->type = IPV6_ICMPV6_ROUTER_ADVERTISEMENT; + icmpv6->mac = interface->mac; + icmpv6->data_len = 0; + break; + default: + return; + } + + ipv6->src = (void*)ipv6_link_local_address; + ipv6->dst = (void*)ipv6_multicast_all_nodes; + ipv6->ttl = 255; + if(bbl_txq_to_buffer(interface->txq, eth) == BBL_TXQ_OK) { + a10nsp_session->stats.packets_tx++; + } +} + static void bbl_a10nsp_ipv4_handler(bbl_a10nsp_interface_s *interface, bbl_session_s *session, @@ -479,6 +595,29 @@ bbl_a10nsp_ipv4_handler(bbl_a10nsp_interface_s *interface, } } +static void +bbl_a10nsp_ipv6_handler(bbl_a10nsp_interface_s *interface, + bbl_session_s *session, + bbl_ethernet_header_s *eth) +{ + bbl_ipv6_s *ipv6 = (bbl_ipv6_s*)eth->next; + bbl_udp_s *udp; + + switch(ipv6->protocol) { + case IPV6_NEXT_HEADER_UDP: + udp = (bbl_udp_s*)ipv6->next; + if(udp->protocol == UDP_PROTOCOL_DHCPV6) { + bbl_a10nsp_dhcpv6_handler(interface, session, eth); + } + break; + case IPV6_NEXT_HEADER_ICMPV6: + bbl_a10nsp_icmpv6_handler(interface, session, eth); + break; + default: + break; + } +} + /** * bbl_a10nsp_rx * @@ -525,6 +664,9 @@ bbl_a10nsp_rx(bbl_a10nsp_interface_s *interface, case ETH_TYPE_IPV4: bbl_a10nsp_ipv4_handler(interface, session, eth); break; + case ETH_TYPE_IPV6: + bbl_a10nsp_ipv6_handler(interface, session, eth); + break; default: break; } diff --git a/code/bngblaster/src/bbl_access.c b/code/bngblaster/src/bbl_access.c index 77924dc6..80b89af2 100644 --- a/code/bngblaster/src/bbl_access.c +++ b/code/bngblaster/src/bbl_access.c @@ -506,12 +506,6 @@ bbl_access_rx_icmpv6(bbl_access_interface_s *interface, session->stats.icmpv6_rx++; - if(session->a10nsp_session) { - /* There is currently no IPv6 support - * for A10NSP terminated sessions today. */ - return; - } - if(session->access_type == ACCESS_TYPE_PPPOE && session->ip6cp_state != BBL_PPP_OPENED) { return; diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index f99d9692..857d2c81 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -982,6 +982,12 @@ json_parse_access_interface(json_t *access_interface, bbl_access_config_s *acces } else { access_config->dhcpv6_enable = g_ctx->config.dhcpv6_enable; } + value = json_object_get(access_interface, "dhcpv6-ldra"); + if(json_is_boolean(value)) { + access_config->dhcpv6_ldra = json_boolean_value(value); + } else { + access_config->dhcpv6_ldra = g_ctx->config.dhcpv6_ldra; + } value = json_object_get(access_interface, "ipv6"); if(json_is_boolean(value)) { access_config->ipv6_enable = json_boolean_value(value); @@ -2252,6 +2258,10 @@ json_parse_config(json_t *root) if(json_is_boolean(value)) { g_ctx->config.dhcpv6_enable = json_boolean_value(value); } + value = json_object_get(section, "ldra"); + if(json_is_boolean(value)) { + g_ctx->config.dhcpv6_ldra = json_boolean_value(value); + } value = json_object_get(section, "ia-na"); if(json_is_boolean(value)) { g_ctx->config.dhcpv6_ia_na = json_boolean_value(value); diff --git a/code/bngblaster/src/bbl_config.h b/code/bngblaster/src/bbl_config.h index 89686f4b..da63efff 100644 --- a/code/bngblaster/src/bbl_config.h +++ b/code/bngblaster/src/bbl_config.h @@ -65,6 +65,7 @@ typedef struct bbl_access_config_ bool ipv6_enable; bool dhcp_enable; bool dhcpv6_enable; + bool dhcpv6_ldra; bool igmp_autostart; uint8_t igmp_version; bool session_traffic_autostart; diff --git a/code/bngblaster/src/bbl_ctx.h b/code/bngblaster/src/bbl_ctx.h index ec36ca9b..ecb1bdbd 100644 --- a/code/bngblaster/src/bbl_ctx.h +++ b/code/bngblaster/src/bbl_ctx.h @@ -288,6 +288,7 @@ typedef struct bbl_ctx_ /* DHCPv6 */ bool dhcpv6_enable; + bool dhcpv6_ldra; bool dhcpv6_ia_na; bool dhcpv6_ia_pd; bool dhcpv6_rapid_commit; diff --git a/code/bngblaster/src/bbl_def.h b/code/bngblaster/src/bbl_def.h index 645aeca4..921566c5 100644 --- a/code/bngblaster/src/bbl_def.h +++ b/code/bngblaster/src/bbl_def.h @@ -62,6 +62,14 @@ #define MOCK_DNS1 134744072 /* 8.8.8.8 */ #define MOCK_DNS2 16843009 /* 1.1.1.1 */ +static const uint8_t mock_dhcpv6_server_duid[] = {0x00, 0x02, 0x00, 0x00, 0x8A, 0xC3, 0x01, 0x01}; +static const ipv6addr_t mock_ipv6_local = {0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +static const ipv6addr_t mock_ipv6_ia_na = {0xFC, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}; +static const ipv6_prefix mock_ipv6_ia_pd = { + .len = 56, + .address = {0xFC, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +}; + /* Interface Send Mask */ #define BBL_SEND_LACP 0x00000001 diff --git a/code/bngblaster/src/bbl_dhcpv6.c b/code/bngblaster/src/bbl_dhcpv6.c index 4c3f718c..c70221e6 100644 --- a/code/bngblaster/src/bbl_dhcpv6.c +++ b/code/bngblaster/src/bbl_dhcpv6.c @@ -205,6 +205,14 @@ bbl_dhcpv6_rx(bbl_session_s *session, bbl_ethernet_header_s *eth, bbl_dhcpv6_s * return; } + if(dhcpv6->type == DHCPV6_MESSAGE_RELAY_REPL) { + if(!dhcpv6->relay_message) { + /* Invalid packet received */ + return; + } + dhcpv6 = dhcpv6->relay_message; + } + /* Ignore packets with wrong transaction identifier */ if(dhcpv6->xid != session->dhcpv6_xid) { return; diff --git a/code/bngblaster/src/bbl_protocols.c b/code/bngblaster/src/bbl_protocols.c index c1b13722..d38a9be0 100644 --- a/code/bngblaster/src/bbl_protocols.c +++ b/code/bngblaster/src/bbl_protocols.c @@ -230,17 +230,53 @@ encode_dhcpv6(uint8_t *buf, uint16_t *len, { uint16_t value_len; - /* Transaction ID */ - *(uint32_t*)buf = htobe32(dhcpv6->xid); - *buf = dhcpv6->type; - BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); - /* Elapsed Time */ - *(uint16_t*)buf = htobe16(DHCPV6_OPTION_ELAPSED_TIME); - BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); - *(uint16_t*)buf = htobe16(sizeof(uint16_t)); - BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); - *(uint16_t*)buf = 0; - BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + if(dhcpv6->type == DHCPV6_MESSAGE_RELAY_FORW || + dhcpv6->type == DHCPV6_MESSAGE_RELAY_REPL) { + /* Type */ + *buf = dhcpv6->type; + BUMP_WRITE_BUFFER(buf, len, sizeof(uint8_t)); + /* Hops */ + *buf = dhcpv6->hops; + /* Link Address */ + BUMP_WRITE_BUFFER(buf, len, sizeof(uint8_t)); + if(dhcpv6->link_address) { + memcpy(buf, dhcpv6->link_address, sizeof(ipv6addr_t)); + } else { + memset(buf, 0x0, sizeof(ipv6addr_t)); + } + BUMP_WRITE_BUFFER(buf, len, sizeof(ipv6addr_t)); + /* Peer Address */ + if(dhcpv6->peer_address) { + memcpy(buf, dhcpv6->peer_address, sizeof(ipv6addr_t)); + } else { + memset(buf, 0x0, sizeof(ipv6addr_t)); + } + BUMP_WRITE_BUFFER(buf, len, sizeof(ipv6addr_t)); + } else { + /* Type/Transaction ID */ + *(uint32_t*)buf = htobe32(dhcpv6->xid); + *buf = dhcpv6->type; + BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); + /* Elapsed Time */ + *(uint16_t*)buf = htobe16(DHCPV6_OPTION_ELAPSED_TIME); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = htobe16(sizeof(uint16_t)); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = 0; + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + } + + /* Relay Message */ + if(dhcpv6->relay_message) { + *(uint16_t*)buf = htobe16(DHCPV6_OPTION_RELAY_MSG); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + value_len = 0; + if(encode_dhcpv6(buf+2, &value_len, dhcpv6->relay_message) != PROTOCOL_SUCCESS) { + return ENCODE_ERROR; + } + *(uint16_t*)buf = htobe16(value_len); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)+value_len); + } /* Client Identifier */ if(dhcpv6->client_duid_len) { *(uint16_t*)buf = htobe16(DHCPV6_OPTION_CLIENTID); @@ -277,14 +313,31 @@ encode_dhcpv6(uint8_t *buf, uint16_t *len, } else if(dhcpv6->ia_na_iaid) { *(uint16_t*)buf = htobe16(DHCPV6_OPTION_IA_NA); BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); - *(uint16_t*)buf = htobe16(12); + if(dhcpv6->ia_na_address) { + *(uint16_t*)buf = htobe16(40); /* length */ + } else { + *(uint16_t*)buf = htobe16(12); /* length */ + } BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); *(uint32_t*)buf = dhcpv6->ia_na_iaid; BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); - *(uint32_t*)buf = 0; /* T1 */ + *(uint32_t*)buf = dhcpv6->ia_na_t1; /* T1 */ BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); - *(uint32_t*)buf = 0; /* T2 */ + *(uint32_t*)buf = dhcpv6->ia_na_t2; /* T2 */ BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); + if(dhcpv6->ia_na_address) { + *(uint16_t*)buf = htobe16(DHCPV6_OPTION_IAADDR); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = htobe16(24); /* length */ + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + memcpy(buf, dhcpv6->ia_na_address, sizeof(ipv6addr_t)); + BUMP_WRITE_BUFFER(buf, len, sizeof(ipv6addr_t)); + *(uint32_t*)buf = dhcpv6->ia_na_preferred_lifetime; + BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); + *(uint32_t*)buf = dhcpv6->ia_na_valid_lifetime; + BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); + } + } /* IA_PD */ if(dhcpv6->ia_pd_option_len) { @@ -297,23 +350,27 @@ encode_dhcpv6(uint8_t *buf, uint16_t *len, } else if(dhcpv6->ia_pd_iaid) { *(uint16_t*)buf = htobe16(DHCPV6_OPTION_IA_PD); BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); - *(uint16_t*)buf = htobe16(41); + *(uint16_t*)buf = htobe16(41); /* length */ BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); *(uint32_t*)buf = dhcpv6->ia_pd_iaid; BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); - *(uint32_t*)buf = 0; /* T1 */ + *(uint32_t*)buf = dhcpv6->ia_pd_t1; /* T1 */ BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); - *(uint32_t*)buf = 0; /* T2 */ + *(uint32_t*)buf = dhcpv6->ia_pd_t2; /* T2 */ BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); *(uint16_t*)buf = htobe16(DHCPV6_OPTION_IAPREFIX); BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); *(uint16_t*)buf = htobe16(25); /* length */ BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); - *(uint32_t*)buf = 0; /* preferred lifetime */ + *(uint32_t*)buf = dhcpv6->ia_pd_preferred_lifetime; BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); - *(uint32_t*)buf = 0; /* valid lifetime */ + *(uint32_t*)buf = dhcpv6->ia_pd_valid_lifetime; BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); - memset(buf, 0x0, sizeof(ipv6_prefix)); + if(dhcpv6->ia_pd_prefix) { + memcpy(buf, dhcpv6->ia_pd_prefix, sizeof(ipv6_prefix)); + } else { + memset(buf, 0x0, sizeof(ipv6_prefix)); + } BUMP_WRITE_BUFFER(buf, len, sizeof(ipv6_prefix)); } /* Option Request Option */ @@ -351,6 +408,7 @@ encode_dhcpv6(uint8_t *buf, uint16_t *len, value_len = strnlen(dhcpv6->access_line->ari, UINT16_MAX); *(uint16_t*)buf = htobe16(value_len+4); BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + /* See TR-177 chapter 5.6.1, R-11! */ *(uint32_t*)buf = htobe32(BROADBAND_FORUM); BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); memcpy(buf, dhcpv6->access_line->ari, value_len); @@ -2506,7 +2564,8 @@ decode_dhcpv6_ia_pd(uint8_t *buf, uint16_t len, bbl_dhcpv6_s *dhcpv6) static protocol_error_t decode_dhcpv6(uint8_t *buf, uint16_t len, uint8_t *sp, uint16_t sp_len, - bbl_dhcpv6_s **_dhcpv6) + bbl_dhcpv6_s **_dhcpv6, + bool relay) { protocol_error_t ret_val = PROTOCOL_SUCCESS; @@ -2522,10 +2581,23 @@ decode_dhcpv6(uint8_t *buf, uint16_t len, dhcpv6 = (bbl_dhcpv6_s*)sp; BUMP_BUFFER(sp, sp_len, sizeof(bbl_dhcpv6_s)); memset(dhcpv6, 0x0, sizeof(bbl_dhcpv6_s)); - dhcpv6->xid = be32toh(*(uint32_t*)buf); - dhcpv6->type = dhcpv6->xid >> 24; - dhcpv6->xid &= DHCPV6_TYPE_MASK; - BUMP_BUFFER(buf, len, sizeof(uint32_t)); + dhcpv6->type = *buf; + if(dhcpv6->type == DHCPV6_MESSAGE_RELAY_FORW || + dhcpv6->type == DHCPV6_MESSAGE_RELAY_REPL) { + if(relay || len < 34) { + return DECODE_ERROR; + } + BUMP_BUFFER(buf, len, sizeof(uint8_t)); + dhcpv6->hops = *buf; + BUMP_BUFFER(buf, len, sizeof(uint8_t)); + dhcpv6->link_address = (ipv6addr_t*)(buf); + BUMP_BUFFER(buf, len, sizeof(ipv6addr_t)); + dhcpv6->peer_address = (ipv6addr_t*)(buf); + BUMP_BUFFER(buf, len, sizeof(ipv6addr_t)); + } else { + dhcpv6->xid = be32toh(*(uint32_t*)buf) & DHCPV6_TYPE_MASK; + BUMP_BUFFER(buf, len, sizeof(uint32_t)); + } while(len >= 4) { option = be16toh(*(uint16_t*)buf); @@ -2564,6 +2636,17 @@ decode_dhcpv6(uint8_t *buf, uint16_t len, } } break; + case DHCPV6_OPTION_INTERFACE_ID: + dhcpv6->interface_id = buf; + dhcpv6->interface_id_len = option_len; + break; + case DHCPV6_OPTION_RELAY_MSG: + if(!(dhcpv6->type == DHCPV6_MESSAGE_RELAY_FORW || dhcpv6->type == DHCPV6_MESSAGE_RELAY_REPL)) { + return DECODE_ERROR; + } + if(decode_dhcpv6(buf, option_len, sp, sp_len, (bbl_dhcpv6_s**)&dhcpv6->relay_message, true) != PROTOCOL_SUCCESS) { + return DECODE_ERROR; + } default: break; } @@ -2975,7 +3058,7 @@ decode_udp(uint8_t *buf, uint16_t len, case DHCPV6_UDP_CLIENT: case DHCPV6_UDP_SERVER: udp->protocol = UDP_PROTOCOL_DHCPV6; - ret_val = decode_dhcpv6(buf, len, sp, sp_len, (bbl_dhcpv6_s**)&udp->next); + ret_val = decode_dhcpv6(buf, len, sp, sp_len, (bbl_dhcpv6_s**)&udp->next, false); break; case BBL_UDP_PORT: udp->protocol = UDP_PROTOCOL_BBL; diff --git a/code/bngblaster/src/bbl_protocols.h b/code/bngblaster/src/bbl_protocols.h index dec5d12f..2301878f 100644 --- a/code/bngblaster/src/bbl_protocols.h +++ b/code/bngblaster/src/bbl_protocols.h @@ -830,7 +830,10 @@ typedef struct bbl_icmpv6_ { typedef struct bbl_dhcpv6_ { uint8_t type; + uint8_t hops; uint32_t xid; + uint8_t *interface_id; + uint8_t interface_id_len; uint8_t *client_duid; uint8_t client_duid_len; uint8_t *server_duid; @@ -858,6 +861,12 @@ typedef struct bbl_dhcpv6_ { uint32_t ia_pd_preferred_lifetime; uint32_t ia_pd_valid_lifetime; access_line_s *access_line; + + /* DHCPv6 Relay Attributes */ + + ipv6addr_t *link_address; + ipv6addr_t *peer_address; + struct bbl_dhcpv6_ *relay_message; } bbl_dhcpv6_s; struct dhcp_header { diff --git a/code/bngblaster/src/bbl_tx.c b/code/bngblaster/src/bbl_tx.c index 6d7863bc..3adade5b 100644 --- a/code/bngblaster/src/bbl_tx.c +++ b/code/bngblaster/src/bbl_tx.c @@ -438,6 +438,7 @@ bbl_tx_encode_packet_dhcpv6_request(bbl_session_s *session) bbl_ipv6_s ipv6 = {0}; bbl_udp_s udp = {0}; bbl_dhcpv6_s dhcpv6 = {0}; + bbl_dhcpv6_s dhcpv6_relay = {0}; access_line_s access_line = {0}; uint8_t mac[ETH_ADDR_LEN]; @@ -446,15 +447,28 @@ bbl_tx_encode_packet_dhcpv6_request(bbl_session_s *session) return IGNORED; } - if(g_ctx->config.dhcpv6_access_line && - (session->agent_circuit_id || session->agent_remote_id) && - session->dhcpv6_state != BBL_DHCP_RELEASE) { - access_line.aci = session->agent_circuit_id; - access_line.ari = session->agent_remote_id; - access_line.up = session->rate_up; - access_line.down = session->rate_down; - access_line.dsl_type = session->dsl_type; - dhcpv6.access_line = &access_line; + if(g_ctx->config.dhcpv6_ldra) { + dhcpv6_relay.type = DHCPV6_MESSAGE_RELAY_FORW; + dhcpv6_relay.peer_address = (void*)session->link_local_ipv6_address; + dhcpv6_relay.relay_message = &dhcpv6; + if(g_ctx->config.dhcpv6_access_line && + (session->agent_circuit_id || session->agent_remote_id)) { + access_line.aci = session->agent_circuit_id; + access_line.ari = session->agent_remote_id; + access_line.up = session->rate_up; + access_line.down = session->rate_down; + access_line.dsl_type = session->dsl_type; + + } + if(!access_line.aci) { + /* The ACI is mapped to the Interface-Id option, + * which is mandatory for relay forward messages. */ + access_line.aci = format_mac_address(session->client_mac); + } + dhcpv6_relay.access_line = &access_line; + udp.next = &dhcpv6_relay; + } else { + udp.next = &dhcpv6; } eth.src = session->client_mac; @@ -491,7 +505,6 @@ bbl_tx_encode_packet_dhcpv6_request(bbl_session_s *session) udp.dst = DHCPV6_UDP_SERVER; udp.src = DHCPV6_UDP_CLIENT; udp.protocol = UDP_PROTOCOL_DHCPV6; - udp.next = &dhcpv6; dhcpv6.xid = session->dhcpv6_xid; dhcpv6.client_duid = session->dhcpv6_duid; dhcpv6.client_duid_len = DUID_LEN; diff --git a/docsrc/sources/configuration/dhcpv6.rst b/docsrc/sources/configuration/dhcpv6.rst index 1d2aafd6..8af8d761 100644 --- a/docsrc/sources/configuration/dhcpv6.rst +++ b/docsrc/sources/configuration/dhcpv6.rst @@ -13,6 +13,9 @@ * - `enable` - This option allows to enable or disable DHCPv6 - true + * - `ldra` + - This option allows to enable or disable LDRA + - false * - `ia-na` - This option allows to enable or disable DHCPv6 IA_NA - true @@ -30,4 +33,9 @@ - 10 * - `access-line` - Add access-line attributes like Agent-Remote/Circuit-Id - - true \ No newline at end of file + - true + +DHCPv6 LDRA (Lightweight DHCPv6 Relay Agent) is defined in +[RFC6221](https://datatracker.ietf.org/doc/html/rfc6221). Adding +access-line information like Agent-Remote-Id or Agent-Circuit-Id +is allowed with LDRA enabled only. diff --git a/docsrc/sources/configuration/interfaces_access.rst b/docsrc/sources/configuration/interfaces_access.rst index 9efe456f..38b4b156 100644 --- a/docsrc/sources/configuration/interfaces_access.rst +++ b/docsrc/sources/configuration/interfaces_access.rst @@ -109,6 +109,9 @@ * - `dhcpv6` - De-/activate DHCPv6 - + * - `dhcpv6-ldra` + - De-/activate DHCPv6 LDRA + - * - `igmp-autostart` - Overwrite IGMP autostart -