diff options
author | Philippe Guibert <philippe.guibert@6wind.com> | 2022-12-29 15:51:26 +0100 |
---|---|---|
committer | Louis Scalbert <louis.scalbert@6wind.com> | 2023-06-05 16:08:51 +0200 |
commit | 61e31c591e10326630ec9297c50b2dd8d04602c1 (patch) | |
tree | e7e3ee322a2f26ef9a1802c5c7d86fff0661195b | |
parent | 2b0226f25bd65dbe357b751aeeb481c09df20382 (diff) | |
download | accel-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.c | 61 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/dhcpv4.h | 11 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 58 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 1 |
4 files changed, 101 insertions, 30 deletions
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; |