summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2022-12-29 15:51:26 +0100
committerLouis Scalbert <louis.scalbert@6wind.com>2023-06-05 16:08:51 +0200
commit61e31c591e10326630ec9297c50b2dd8d04602c1 (patch)
treee7e3ee322a2f26ef9a1802c5c7d86fff0661195b
parent2b0226f25bd65dbe357b751aeeb481c09df20382 (diff)
downloadaccel-ppp-61e31c591e10326630ec9297c50b2dd8d04602c1.tar.gz
accel-ppp-61e31c591e10326630ec9297c50b2dd8d04602c1.zip
ipoe: add dhcp link selection sub-option
Add the support of DHCP option 82 "Agent Information" sub-option 5 "link selection". The IPv4 value can be specified in the [ipoe] "link-selection" configuration option. Link: https://www.rfc-editor.org/rfc/rfc3527.html Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.c61
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.h11
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c58
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h1
4 files changed, 101 insertions, 30 deletions
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c
index 5218a73b..466dfee6 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4.c
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.c
@@ -430,7 +430,7 @@ void dhcpv4_packet_free(struct dhcpv4_packet *pack)
mempool_free(pack);
}
-int dhcpv4_parse_opt82(struct dhcpv4_option *opt, uint8_t **agent_circuit_id, uint8_t **agent_remote_id)
+int dhcpv4_parse_opt82(struct dhcpv4_option *opt, uint8_t **agent_circuit_id, uint8_t **agent_remote_id, uint8_t **link_selection)
{
uint8_t *ptr = opt->data;
uint8_t *endptr = ptr + opt->len;
@@ -450,6 +450,8 @@ int dhcpv4_parse_opt82(struct dhcpv4_option *opt, uint8_t **agent_circuit_id, ui
*agent_circuit_id = ptr - 1;
else if (type == 2)
*agent_remote_id = ptr - 1;
+ else if (type == 5)
+ *link_selection = ptr - 1;
ptr += len;
}
@@ -457,25 +459,51 @@ int dhcpv4_parse_opt82(struct dhcpv4_option *opt, uint8_t **agent_circuit_id, ui
return 0;
}
-int dhcpv4_packet_insert_opt82(struct dhcpv4_packet *pack, const char *agent_circuit_id, const char *agent_remote_id)
+int dhcpv4_packet_insert_opt82(struct dhcpv4_packet *pack, const char *agent_circuit_id, const char *agent_remote_id, const char *link_selection)
{
int len1 = strlen(agent_circuit_id);
- int len2 = strlen(agent_remote_id);
- uint8_t *data = _malloc(4 + len1 + len2);
- uint8_t *ptr = data;
+ int len2 = 0;
+ int len5 = 0;
+ int opt82_len;
+ uint8_t *data;
+ uint8_t *ptr;
int r;
+ struct in_addr link_select = {0};
pack->ptr--;
- *ptr++ = 1;
+ opt82_len = len1 + 2;
+ if (agent_remote_id) {
+ len2 = strlen(agent_remote_id);
+ opt82_len += len2 + 2;
+ }
+ if (link_selection && inet_pton(AF_INET, link_selection, &link_select) > 0) {
+ len5 = sizeof(struct in_addr);
+ opt82_len += len5 + 2;
+ }
+
+ data = _malloc(opt82_len);
+ ptr = data;
+
+ /* Agent Circuit ID */
+ *ptr++ = 1; /* Sub-Option 1 */
*ptr++ = len1;
memcpy(ptr, agent_circuit_id, len1); ptr += len1;
- *ptr++ = 2;
- *ptr++ = len2;
- memcpy(ptr, agent_remote_id, len2); ptr += len2;
+ /* Agent Remote ID */
+ if (len2 > 0) {
+ *ptr++ = 2; /* Sub-Option 2 */
+ *ptr++ = len2;
+ memcpy(ptr, agent_remote_id, len2); ptr += len2;
+ }
+ /* Link-Selection */
+ if (len5 > 0) {
+ *ptr++ = 5; /* Sub-Option 5 */
+ *ptr++ = len5;
+ memcpy(ptr, &link_select, len5); ptr += len5;
+ }
- r = dhcpv4_packet_add_opt(pack, 82, data, 4 + len1 + len2);
+ r = dhcpv4_packet_add_opt(pack, 82, data, opt82_len);
_free(data);
*pack->ptr++ = 255;
@@ -1055,7 +1083,7 @@ void dhcpv4_relay_free(struct dhcpv4_relay *r, struct triton_context_t *ctx)
pthread_mutex_unlock(&relay_lock);
}
-int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request, uint32_t server_id, const char *agent_circuit_id, const char *agent_remote_id)
+int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request, uint32_t server_id, const char *agent_circuit_id, const char *agent_remote_id, const char *link_selection)
{
int n;
int len = request->ptr - request->data;
@@ -1063,7 +1091,8 @@ int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request,
struct dhcpv4_option *opt = NULL;
uint32_t _server_id;
- if (!request->relay_agent && agent_remote_id && dhcpv4_packet_insert_opt82(request, agent_circuit_id, agent_remote_id))
+ if (!request->relay_agent && (agent_remote_id || link_selection) &&
+ dhcpv4_packet_insert_opt82(request, agent_circuit_id, agent_remote_id, link_selection))
return -1;
request->hdr->giaddr = relay->giaddr;
@@ -1104,7 +1133,8 @@ int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request,
int dhcpv4_relay_send_release(struct dhcpv4_relay *relay, uint8_t *chaddr, uint32_t xid, uint32_t ciaddr,
struct dhcpv4_option *client_id, struct dhcpv4_option *relay_agent,
- const char *agent_circuit_id, const char *agent_remote_id)
+ const char *agent_circuit_id, const char *agent_remote_id,
+ const char *link_selection)
{
struct dhcpv4_packet *pack;
int n, len;
@@ -1135,9 +1165,10 @@ int dhcpv4_relay_send_release(struct dhcpv4_relay *relay, uint8_t *chaddr, uint3
if (relay_agent && dhcpv4_packet_add_opt(pack, 82, relay_agent->data, relay_agent->len))
goto out_err;
- else if (!relay_agent && agent_remote_id) {
+ else if (!relay_agent && (agent_remote_id || link_selection)) {
pack->ptr++;
- if (dhcpv4_packet_insert_opt82(pack, agent_circuit_id, agent_remote_id))
+ if (dhcpv4_packet_insert_opt82(pack, agent_circuit_id, agent_remote_id,
+ link_selection))
goto out_err;
pack->ptr--;
}
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.h b/accel-pppd/ctrl/ipoe/dhcpv4.h
index 796b858f..f5859f7c 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4.h
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.h
@@ -114,11 +114,12 @@ void dhcpv4_free(struct dhcpv4_serv *);
struct dhcpv4_relay *dhcpv4_relay_create(const char *addr, in_addr_t giaddr, struct triton_context_t *ctx, triton_event_func recv);
void dhcpv4_relay_free(struct dhcpv4_relay *, struct triton_context_t *);
int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request, uint32_t server_id,
- const char *agent_circuit_id, const char *agent_remote_id);
+ const char *agent_circuit_id, const char *agent_remote_id,
+ const char *link_selection);
int dhcpv4_relay_send_release(struct dhcpv4_relay *relay, uint8_t *chaddr, uint32_t xid, uint32_t ciaddr,
struct dhcpv4_option *client_id, struct dhcpv4_option *relay_agent,
- const char *agent_circuit_id, const char *agent_remote_id);
-
+ const char *agent_circuit_id, const char *agent_remote_id,
+ const char *link_selection);
int dhcpv4_send_reply(int msg_type, struct dhcpv4_serv *serv, struct dhcpv4_packet *req,
uint32_t yiaddr, uint32_t siaddr, uint32_t router, uint32_t mask,
int lease_time, int renew_time, int rebind_time, struct dhcpv4_packet *relay_reply);
@@ -128,7 +129,7 @@ void dhcpv4_send_notify(struct dhcpv4_serv *serv, struct dhcpv4_packet *req, uns
void dhcpv4_packet_ref(struct dhcpv4_packet *pack);
struct dhcpv4_option *dhcpv4_packet_find_opt(struct dhcpv4_packet *pack, int type);
-int dhcpv4_packet_insert_opt82(struct dhcpv4_packet *pack, const char *agent_circuit_id, const char *agent_remote_id);
+int dhcpv4_packet_insert_opt82(struct dhcpv4_packet *pack, const char *agent_circuit_id, const char *agent_remote_id, const char *link_selection);
void dhcpv4_packet_free(struct dhcpv4_packet *pack);
struct dhcpv4_packet *dhcpv4_clone_radius(struct rad_packet_t *);
@@ -137,7 +138,7 @@ void dhcpv4_print_options(struct dhcpv4_packet *, void (*)(const char *, ...));
void dhcpv4_print_packet(struct dhcpv4_packet *pack, int relay, void (*print)(const char *fmt, ...));
-int dhcpv4_parse_opt82(struct dhcpv4_option *opt, uint8_t **agent_circuit_id, uint8_t **agent_remote_id);
+int dhcpv4_parse_opt82(struct dhcpv4_option *opt, uint8_t **agent_circuit_id, uint8_t **agent_remote_id, uint8_t **link_selection);
int dhcpv4_get_ip(struct dhcpv4_serv *serv, uint32_t *yiaddr, uint32_t *siaddr, int *mask);
void dhcpv4_put_ip(struct dhcpv4_serv *serv, uint32_t ip);
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index b6ca46c4..4a4f95d4 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -173,6 +173,7 @@ static int conf_renew_time = LEASE_TIME/2;
static int conf_rebind_time = LEASE_TIME/2 + LEASE_TIME/4 + LEASE_TIME/8;
static int conf_verbose;
static const char *conf_agent_remote_id;
+static const char *conf_link_selection;
static int conf_proto;
static LIST_HEAD(conf_offer_delay);
static const char *conf_vlan_name;
@@ -258,6 +259,7 @@ static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct d
uint8_t *agent_circuit_id = NULL;
uint8_t *agent_remote_id = NULL;
+ uint8_t *link_selection = NULL;
int opt82_match;
if (opt82_ses)
@@ -274,9 +276,10 @@ static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct d
return ses;
}
- if (!conf_check_mac_change || (pack->relay_agent && dhcpv4_parse_opt82(pack->relay_agent, &agent_circuit_id, &agent_remote_id))) {
+ if (!conf_check_mac_change || (pack->relay_agent && dhcpv4_parse_opt82(pack->relay_agent, &agent_circuit_id, &agent_remote_id, &link_selection))) {
agent_circuit_id = NULL;
agent_remote_id = NULL;
+ link_selection = NULL;
}
list_for_each_entry(ses, &serv->sessions, entry) {
@@ -288,12 +291,18 @@ static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct d
if (opt82_match && agent_remote_id && !ses->agent_remote_id)
opt82_match = 0;
+ if (opt82_match && link_selection && !ses->link_selection)
+ opt82_match = 0;
+
if (opt82_match && !agent_circuit_id && ses->agent_circuit_id)
opt82_match = 0;
if (opt82_match && !agent_remote_id && ses->agent_remote_id)
opt82_match = 0;
+ if (opt82_match && !link_selection && ses->link_selection)
+ opt82_match = 0;
+
if (opt82_match && agent_circuit_id) {
if (*agent_circuit_id != *ses->agent_circuit_id)
opt82_match = 0;
@@ -310,6 +319,14 @@ static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct d
opt82_match = 0;
}
+ if (opt82_match && link_selection) {
+ if (*link_selection != *ses->link_selection)
+ opt82_match = 0;
+
+ if (memcmp(link_selection + 1, ses->link_selection + 1, *link_selection))
+ opt82_match = 0;
+ }
+
if (opt82_match && opt82_ses)
*opt82_ses = ses;
@@ -350,12 +367,18 @@ static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct d
if (opt82_match && agent_remote_id && !ses->agent_remote_id)
continue;
+ if (opt82_match && link_selection && !ses->link_selection)
+ continue;
+
if (opt82_match && !agent_circuit_id && ses->agent_circuit_id)
continue;
if (opt82_match && !agent_remote_id && ses->agent_remote_id)
continue;
+ if (opt82_match && !link_selection && ses->link_selection)
+ continue;
+
if (opt82_match && agent_circuit_id) {
if (*agent_circuit_id != *ses->agent_circuit_id)
continue;
@@ -372,6 +395,14 @@ static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct d
continue;
}
+ if (opt82_match && link_selection) {
+ if (*link_selection != *ses->link_selection)
+ continue;
+
+ if (memcmp(link_selection + 1, ses->link_selection + 1, *link_selection))
+ continue;
+ }
+
*opt82_ses = ses;
break;
}
@@ -417,7 +448,7 @@ static void ipoe_relay_timeout(struct triton_timer_t *t)
ap_session_terminate(&ses->ses, TERM_LOST_CARRIER, 1);
} else
- dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id);
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id, conf_link_selection);
}
@@ -684,7 +715,7 @@ cont:
ap_session_set_ifindex(&ses->ses);
if (ses->dhcpv4_request && ses->serv->dhcpv4_relay) {
- dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id);
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id, conf_link_selection);
ses->timer.expire = ipoe_relay_timeout;
ses->timer.period = conf_relay_timeout * 1000;
@@ -1077,7 +1108,7 @@ static void ipoe_session_activate(struct dhcpv4_packet *pack)
ses->dhcpv4_request = pack;
if (ses->serv->dhcpv4_relay)
- dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id);
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id, conf_link_selection);
else
__ipoe_session_activate(ses);
}
@@ -1097,7 +1128,7 @@ static void ipoe_session_keepalive(struct dhcpv4_packet *pack)
ses->xid = ses->dhcpv4_request->hdr->xid;
if (/*ses->ses.state == AP_STATE_ACTIVE &&*/ ses->serv->dhcpv4_relay) {
- dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id);
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id, ses->serv->ifname, conf_agent_remote_id, conf_link_selection);
return;
}
@@ -1121,7 +1152,7 @@ static void ipoe_session_decline(struct dhcpv4_packet *pack)
}
if (pack->msg_type == DHCPDECLINE && ses->serv->dhcpv4_relay)
- dhcpv4_relay_send(ses->serv->dhcpv4_relay, pack, 0, ses->serv->ifname, conf_agent_remote_id);
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, pack, 0, ses->serv->ifname, conf_agent_remote_id, conf_link_selection);
dhcpv4_packet_free(pack);
@@ -1233,7 +1264,7 @@ static void ipoe_session_finished(struct ap_session *s)
dhcpv4_put_ip(ses->serv->dhcpv4, ses->yiaddr);
if (ses->relay_addr && ses->serv->dhcpv4_relay)
- dhcpv4_relay_send_release(ses->serv->dhcpv4_relay, ses->hwaddr, ses->xid, ses->yiaddr, ses->client_id, ses->relay_agent, ses->serv->ifname, conf_agent_remote_id);
+ dhcpv4_relay_send_release(ses->serv->dhcpv4_relay, ses->hwaddr, ses->xid, ses->yiaddr, ses->client_id, ses->relay_agent, ses->serv->ifname, conf_agent_remote_id, conf_link_selection);
if (ses->dhcpv4)
dhcpv4_free(ses->dhcpv4);
@@ -1382,7 +1413,7 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
ses->relay_agent->data = (uint8_t *)(ses->relay_agent + 1);
memcpy(ses->relay_agent->data, pack->relay_agent->data, pack->relay_agent->len);
ptr += sizeof(struct dhcpv4_option) + pack->relay_agent->len;
- if (dhcpv4_parse_opt82(ses->relay_agent, &ses->agent_circuit_id, &ses->agent_remote_id))
+ if (dhcpv4_parse_opt82(ses->relay_agent, &ses->agent_circuit_id, &ses->agent_remote_id, &ses->link_selection))
ses->relay_agent = NULL;
}
@@ -1440,6 +1471,7 @@ static void ipoe_ses_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packe
int opt82_match;
uint8_t *agent_circuit_id = NULL;
uint8_t *agent_remote_id = NULL;
+ uint8_t *link_selection = NULL;
if (conf_verbose) {
log_ppp_info2("recv ");
@@ -1453,9 +1485,10 @@ static void ipoe_ses_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packe
return;
}
- if (pack->relay_agent && dhcpv4_parse_opt82(pack->relay_agent, &agent_circuit_id, &agent_remote_id)) {
+ if (pack->relay_agent && dhcpv4_parse_opt82(pack->relay_agent, &agent_circuit_id, &agent_remote_id, &link_selection)) {
agent_circuit_id = NULL;
agent_remote_id = NULL;
+ link_selection = NULL;
}
opt82_match = pack->relay_agent != NULL;
@@ -1515,7 +1548,7 @@ static void ipoe_ses_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packe
if (pack->server_id == ses->siaddr)
dhcpv4_send_nak(dhcpv4, pack, "Wrong session");
else if (ses->serv->dhcpv4_relay)
- dhcpv4_relay_send(ses->serv->dhcpv4_relay, pack, 0, ses->serv->ifname, conf_agent_remote_id);
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, pack, 0, ses->serv->ifname, conf_agent_remote_id, conf_link_selection);
triton_context_call(ses->ctrl.ctx, (triton_event_func)__ipoe_session_terminate, &ses->ses);
} else {
@@ -3802,6 +3835,7 @@ static void load_config(void)
const char *opt;
struct conf_sect_t *s = conf_get_section("ipoe");
struct conf_option_t *opt1;
+ struct in_addr dummy;
if (!s)
return;
@@ -3969,6 +4003,10 @@ static void load_config(void)
else
conf_agent_remote_id = NULL;
+ opt = conf_get_opt("ipoe", "link-selection");
+ if (opt && inet_pton(AF_INET, opt, &dummy) > 0)
+ conf_link_selection = opt;
+
opt = conf_get_opt("ipoe", "ipv6");
if (opt)
conf_ipv6 = atoi(opt);
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index 75948b1c..07dce1e2 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -86,6 +86,7 @@ struct ipoe_session {
struct dhcpv4_option *relay_agent;
uint8_t *agent_circuit_id;
uint8_t *agent_remote_id;
+ uint8_t *link_selection;
uint32_t xid;
uint32_t giaddr;
uint32_t yiaddr;