summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Eshenko <dmitriy.eshenko@accel-ppp.org>2023-06-09 20:02:02 +0300
committerGitHub <noreply@github.com>2023-06-09 20:02:02 +0300
commit3606825c9664f9139c0fb487ec87d9ba4a889229 (patch)
tree9350af71560e892762a90d3c87549c06552943e5
parentefb533508b9caf6e2e389103a96a1ce3ef6b7c89 (diff)
parent0230ce98fe4188a98fd9d97ac0ee8e6ee771e2fc (diff)
downloadaccel-ppp-3606825c9664f9139c0fb487ec87d9ba4a889229.tar.gz
accel-ppp-3606825c9664f9139c0fb487ec87d9ba4a889229.zip
Merge pull request #83 from louis-6wind/add-link-selection
Add support of Link Selection DHCP sub-option RFC3527
-rw-r--r--accel-pppd/accel-ppp.conf.518
-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
5 files changed, 119 insertions, 30 deletions
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index 09c4597..4424400 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -383,6 +383,24 @@ If ip-unnumbered=1 accel-ppp will always assign /32 mask.
.br
Default value is 1.
.TP
+.BI "agent-remote-id=" string
+Specifies the DCHP option 82 sub-option 2 to be inserted by the DHCP Relay.
+.br
+The purpose of the sub-option is documented in section 3.2 of RFC3046.
+.br
+If neither the
+.B link-selection
+option nor this option is present, option 82 is not inserted by the DCHP Relay Agent.
+.TP
+.BI "link-selection=" ipv4_address
+Specifies option 82 sub-option 5 as per RFC3527 to be added by dhcp relay. The value stands for the subnet to be selected by the DHCP server to associate the request to a specific subnet.
+.br
+The purpose of the sub-option is documented in RFC3527.
+.br
+If neither the
+.B agent-remote-id
+option nor this option is present, option 82 is not inserted by the DCHP Relay Agent.
+.TP
.BI "interface=" [re:]name[,mode=L2|L3][,shared=0|1][,start=dhcpv4|up|auto]
.BI "" [,range=x.x.x.x/mask][,ifcfg=0|1]
.BI "" [,relay=x.x.x.x]
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c
index 5218a73..466dfee 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 796b858..f5859f7 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 b6ca46c..4a4f95d 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 75948b1..07dce1e 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;