summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl/ipoe/ipoe.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/ctrl/ipoe/ipoe.c')
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c440
1 files changed, 314 insertions, 126 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 711dca3..14e8d37 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -59,6 +59,7 @@ static int conf_attr_dhcp_mask;
static int conf_attr_l4_redirect;
#endif
static int conf_l4_redirect_table;
+static const char *conf_relay;
#ifdef USE_LUA
static const char *conf_lua_username_func;
@@ -109,46 +110,54 @@ static void ipoe_serv_close(struct triton_context_t *ctx);
static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct dhcpv4_packet *pack)
{
struct ipoe_session *ses;
- struct ipoe_session *ses1 = NULL;
+
+ uint8_t *agent_circuit_id = NULL;
+ uint8_t *agent_remote_id = NULL;
- list_for_each_entry(ses, &serv->sessions, entry) {
- if (pack->hdr->giaddr != ses->giaddr)
- continue;
+ if (pack->relay_agent && dhcpv4_parse_opt82(pack->relay_agent, &agent_circuit_id, &agent_remote_id)) {
+ agent_circuit_id = NULL;
+ agent_remote_id = NULL;
+ }
- if (pack->agent_circuit_id && !ses->agent_circuit_id)
+ list_for_each_entry(ses, &serv->sessions, entry) {
+ if (agent_circuit_id && !ses->agent_circuit_id)
continue;
- if (pack->agent_remote_id && !ses->agent_remote_id)
+ if (agent_remote_id && !ses->agent_remote_id)
continue;
- if (!pack->agent_circuit_id && ses->agent_circuit_id)
+ if (!agent_circuit_id && ses->agent_circuit_id)
continue;
- if (!pack->agent_remote_id && ses->agent_remote_id)
+ if (!agent_remote_id && ses->agent_remote_id)
continue;
- if (pack->agent_circuit_id) {
- if (pack->agent_circuit_id->len != ses->agent_circuit_id->len)
+ if (agent_circuit_id) {
+ if (*agent_circuit_id != *ses->agent_circuit_id)
continue;
- if (memcmp(pack->agent_circuit_id->data, ses->agent_circuit_id->data, pack->agent_circuit_id->len))
+ if (memcmp(agent_circuit_id + 1, ses->agent_circuit_id + 1, *agent_circuit_id))
continue;
}
- if (pack->agent_remote_id) {
- if (pack->agent_remote_id->len != ses->agent_remote_id->len)
+ if (agent_remote_id) {
+ if (*agent_remote_id != *ses->agent_remote_id)
continue;
- if (memcmp(pack->agent_remote_id->data, ses->agent_remote_id->data, pack->agent_remote_id->len))
+ if (memcmp(agent_remote_id + 1, ses->agent_remote_id + 1, *agent_remote_id))
continue;
-
+
return ses;
}
+
+ if (memcmp(pack->hdr->chaddr, ses->hwaddr, 6))
+ continue;
+
+ return ses;
- if (pack->client_id && !ses->client_id)
+ /*if (pack->client_id && !ses->client_id)
continue;
if (!pack->client_id && ses->client_id)
continue;
-
if (pack->client_id) {
if (pack->client_id->len != ses->client_id->len)
@@ -157,18 +166,15 @@ static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct d
continue;
}
- if (memcmp(pack->hdr->chaddr, ses->hwaddr, 6))
- continue;
-
ses1 = ses;
if (pack->hdr->xid != ses->xid)
continue;
- return ses;
+ return ses;*/
}
- return ses1;
+ return NULL;
}
static void ipoe_session_timeout(struct triton_timer_t *t)
@@ -177,7 +183,7 @@ static void ipoe_session_timeout(struct triton_timer_t *t)
triton_timer_del(t);
- log_ppp_info2("session timed out\n");
+ log_ppp_info2("ipoe: session timed out\n");
ap_session_terminate(&ses->ses, TERM_LOST_CARRIER, 0);
}
@@ -204,10 +210,13 @@ static void ipoe_change_l4_redirect(struct ipoe_session *ses, int del)
else
addr = ses->yiaddr;
- if (del)
+ if (del) {
iprule_del(addr, conf_l4_redirect_table);
- else
+ ses->l4_redirect_set = 0;
+ } else {
iprule_add(addr, conf_l4_redirect_table);
+ ses->l4_redirect_set = 1;
+ }
}
static void ipoe_change_addr(struct ipoe_session *ses, in_addr_t newaddr)
@@ -215,6 +224,7 @@ static void ipoe_change_addr(struct ipoe_session *ses, in_addr_t newaddr)
}
+static void __ipoe_session_start(struct ipoe_session *ses);
static void ipoe_session_start(struct ipoe_session *ses)
{
int r;
@@ -225,6 +235,7 @@ static void ipoe_session_start(struct ipoe_session *ses)
if (ses->serv->opt_shared == 0 && (!ses->ses.ipv4 || ses->ses.ipv4->peer_addr == ses->yiaddr)) {
strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN);
ses->ses.ifindex = ses->serv->ifindex;
+ ses->ctrl.dont_ifcfg = 1;
} else if (ses->ifindex == -1) {
pthread_mutex_lock(&uc_lock);
if (!list_empty(&uc_list)) {
@@ -289,6 +300,18 @@ static void ipoe_session_start(struct ipoe_session *ses)
return;
}
+ if (ses->dhcpv4_request && ses->serv->dhcpv4_relay) {
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id);
+
+ ses->timer.expire = ipoe_session_timeout;
+ ses->timer.expire_tv.tv_sec = conf_offer_timeout;
+ triton_timer_add(&ses->ctx, &ses->timer, 0);
+ } else
+ __ipoe_session_start(ses);
+}
+
+static void __ipoe_session_start(struct ipoe_session *ses)
+{
if (!ses->yiaddr) {
dhcpv4_get_ip(ses->serv->dhcpv4, &ses->yiaddr, &ses->siaddr, &ses->mask);
if (ses->yiaddr)
@@ -320,9 +343,9 @@ static void ipoe_session_start(struct ipoe_session *ses)
if (!ses->mask)
ses->mask = 24;
-
+
if (ses->dhcpv4_request) {
- dhcpv4_send_reply(DHCPOFFER, ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->mask, conf_lease_time);
+ dhcpv4_send_reply(DHCPOFFER, ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->mask, ses->lease_time, ses->dhcpv4_relay_reply);
dhcpv4_packet_free(ses->dhcpv4_request);
ses->dhcpv4_request = NULL;
@@ -338,38 +361,66 @@ static void ipoe_session_start(struct ipoe_session *ses)
}
}
-static void ipoe_ifcfg_add(struct ipoe_session *ses)
+static void ipoe_serv_add_addr(struct ipoe_serv *serv, in_addr_t addr)
{
struct ifaddr *a;
- struct ipoe_serv *serv = ses->serv;
- int f = 0;
pthread_mutex_lock(&serv->lock);
- if (ses->serv->opt_shared) {
- list_for_each_entry(a, &serv->addr_list, entry) {
- if (a->addr == ses->siaddr) {
- f = 1;
- break;
+ list_for_each_entry(a, &serv->addr_list, entry) {
+ if (a->addr == addr) {
+ a->refs++;
+ pthread_mutex_unlock(&serv->lock);
+
+ return;
+ }
+ }
+
+ a = _malloc(sizeof(*a));
+ a->addr = addr;
+ a->refs = 1;
+ list_add_tail(&a->entry, &serv->addr_list);
+
+ if (ipaddr_add(serv->ifindex, a->addr, 32))
+ log_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname);
+
+ pthread_mutex_unlock(&serv->lock);
+}
+
+static void ipoe_serv_del_addr(struct ipoe_serv *serv, in_addr_t addr)
+{
+ struct ifaddr *a;
+
+ pthread_mutex_lock(&serv->lock);
+
+ list_for_each_entry(a, &serv->addr_list, entry) {
+ if (a->addr == addr) {
+ if (--a->refs == 0) {
+ if (ipaddr_del(serv->ifindex, a->addr))
+ log_warn("ipoe: failed to delete addess from interface '%s'\n", serv->ifname);
+ list_del(&a->entry);
+ _free(a);
}
+ break;
}
- if (!f) {
- a = _malloc(sizeof(*a));
- a->addr = ses->siaddr;
- a->refs = 1;
- list_add_tail(&a->entry, &serv->addr_list);
-
- if (ipaddr_add(serv->ifindex, a->addr, 32))
- log_ppp_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname);
- } else
- a->refs++;
- } else {
+ }
+
+ pthread_mutex_unlock(&serv->lock);
+}
+
+static void ipoe_ifcfg_add(struct ipoe_session *ses)
+{
+ struct ipoe_serv *serv = ses->serv;
+
+ if (ses->serv->opt_shared || ses->serv->dhcpv4_relay)
+ ipoe_serv_add_addr(ses->serv, ses->siaddr);
+ else {
+ pthread_mutex_lock(&serv->lock);
if (ipaddr_add(serv->ifindex, ses->siaddr, 32))
log_ppp_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname);
+ pthread_mutex_unlock(&serv->lock);
}
- pthread_mutex_unlock(&serv->lock);
-
if (iproute_add(serv->ifindex, ses->siaddr, ses->yiaddr))
log_ppp_warn("ipoe: failed to add route to interface '%s'\n", serv->ifname);
@@ -378,34 +429,22 @@ static void ipoe_ifcfg_add(struct ipoe_session *ses)
static void ipoe_ifcfg_del(struct ipoe_session *ses)
{
- struct ifaddr *a;
struct ipoe_serv *serv = ses->serv;
if (iproute_del(serv->ifindex, ses->yiaddr))
log_ppp_warn("ipoe: failed to delete route from interface '%s'\n", serv->ifname);
- pthread_mutex_lock(&serv->lock);
-
- if (ses->serv->opt_shared) {
- list_for_each_entry(a, &serv->addr_list, entry) {
- if (a->addr == ses->siaddr)
- break;
- }
- if (--a->refs == 0) {
- if (ipaddr_del(serv->ifindex, a->addr))
- log_ppp_warn("ipoe: failed to delete addess from interface '%s'\n", serv->ifname);
- list_del(&a->entry);
- _free(a);
- }
+ if (ses->serv->opt_shared || ses->serv->dhcpv4_relay) {
+ ipoe_serv_del_addr(ses->serv, ses->siaddr);
} else {
+ pthread_mutex_lock(&serv->lock);
if (ipaddr_del(serv->ifindex, ses->siaddr))
log_ppp_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname);
+ pthread_mutex_unlock(&serv->lock);
}
-
- pthread_mutex_unlock(&serv->lock);
}
-static void ipoe_session_activate(struct ipoe_session *ses)
+static void __ipoe_session_activate(struct ipoe_session *ses)
{
uint32_t addr;
@@ -420,8 +459,7 @@ static void ipoe_session_activate(struct ipoe_session *ses)
ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 0);
return;
}
- } else
- ses->ctrl.dont_ifcfg = 1;
+ }
if (ses->serv->opt_ifcfg)
ipoe_ifcfg_add(ses);
@@ -433,7 +471,7 @@ static void ipoe_session_activate(struct ipoe_session *ses)
if (ses->dhcpv4_request) {
if (ses->ses.state == AP_STATE_ACTIVE)
- dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->mask, conf_lease_time);
+ dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->mask, ses->lease_time, ses->dhcpv4_relay_reply);
else
dhcpv4_send_nak(ses->serv->dhcpv4, ses->dhcpv4_request);
@@ -442,16 +480,36 @@ static void ipoe_session_activate(struct ipoe_session *ses)
}
}
-static void ipoe_session_keepalive(struct ipoe_session *ses)
+static void ipoe_session_activate(struct ipoe_session *ses)
+{
+ if (ses->serv->dhcpv4_relay)
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, ses->dhcpv4_request, ses->relay_server_id);
+ else
+ __ipoe_session_activate(ses);
+}
+
+static void ipoe_session_keepalive(struct dhcpv4_packet *pack)
{
+ struct ipoe_session *ses = container_of(triton_context_self(), typeof(*ses), ctx);
+
+ if (ses->dhcpv4_request)
+ dhcpv4_packet_free(ses->dhcpv4_request);
+
+ ses->dhcpv4_request = pack;
+
if (ses->timer.tpd)
triton_timer_mod(&ses->timer, 0);
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);
+ return;
+ }
- if (ses->ses.state == AP_STATE_ACTIVE)
- dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->mask, conf_lease_time);
- else
+ if (ses->ses.state == AP_STATE_ACTIVE) {
+ dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->mask, ses->lease_time, ses->dhcpv4_relay_reply);
+ } else
dhcpv4_send_nak(ses->serv->dhcpv4, ses->dhcpv4_request);
dhcpv4_packet_free(ses->dhcpv4_request);
@@ -520,6 +578,9 @@ static void ipoe_session_finished(struct ap_session *s)
if (ses->dhcp_addr)
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);
if (ses->ifcfg)
ipoe_ifcfg_del(ses);
@@ -534,7 +595,7 @@ static void ipoe_session_terminate(struct ap_session *s, int hard)
{
struct ipoe_session *ses = container_of(s, typeof(*ses), ses);
- if (ses->l4_redirect)
+ if (ses->l4_redirect_set)
ipoe_change_l4_redirect(ses, 1);
ap_session_finished(s);
@@ -556,7 +617,7 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
struct ipoe_session *ses;
int dlen = 0;
uint8_t *ptr;
-
+
ses = mempool_alloc(ses_pool);
if (!ses) {
log_emerg("out of memery\n");
@@ -574,15 +635,13 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
ses->xid = pack->hdr->xid;
memcpy(ses->hwaddr, pack->hdr->chaddr, 6);
ses->giaddr = pack->hdr->giaddr;
+ ses->lease_time = conf_lease_time;
- if (pack->agent_circuit_id)
- dlen += sizeof(struct dhcp_opt) + pack->agent_circuit_id->len;
-
- if (pack->agent_remote_id)
- dlen += sizeof(struct dhcp_opt) + pack->agent_remote_id->len;
-
if (pack->client_id)
- dlen += sizeof(struct dhcp_opt) + pack->client_id->len;
+ dlen += sizeof(struct dhcpv4_option) + pack->client_id->len;
+
+ if (pack->relay_agent)
+ dlen += sizeof(struct dhcpv4_option) + pack->relay_agent->len;
if (dlen) {
ses->data = _malloc(dlen);
@@ -594,25 +653,20 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
ptr = ses->data;
}
- if (pack->agent_circuit_id) {
- ses->agent_circuit_id = (struct dhcp_opt *)ptr;
- ses->agent_circuit_id->len = pack->agent_circuit_id->len;
- memcpy(ses->agent_circuit_id->data, pack->agent_circuit_id->data, pack->agent_circuit_id->len);
- ptr += sizeof(struct dhcp_opt) + pack->agent_circuit_id->len;
- }
-
- if (pack->agent_remote_id) {
- ses->agent_remote_id = (struct dhcp_opt *)ptr;
- ses->agent_remote_id->len = pack->agent_remote_id->len;
- memcpy(ses->agent_remote_id->data, pack->agent_remote_id->data, pack->agent_remote_id->len);
- ptr += sizeof(struct dhcp_opt) + pack->agent_remote_id->len;
- }
-
if (pack->client_id) {
- ses->client_id = (struct dhcp_opt *)ptr;
+ ses->client_id = (struct dhcpv4_option *)ptr;
ses->client_id->len = pack->client_id->len;
memcpy(ses->client_id->data, pack->client_id->data, pack->client_id->len);
- ptr += sizeof(struct dhcp_opt) + pack->client_id->len;
+ ptr += sizeof(struct dhcpv4_option) + pack->client_id->len;
+ }
+
+ if (pack->relay_agent) {
+ ses->relay_agent = (struct dhcpv4_option *)ptr;
+ ses->relay_agent->len = pack->relay_agent->len;
+ 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))
+ ses->relay_agent = NULL;
}
ses->ctx.before_switch = log_switch;
@@ -661,24 +715,25 @@ static void ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p
ses = ipoe_session_lookup(serv, pack);
if (!ses) {
ses = ipoe_session_create_dhcpv4(serv, pack);
+ if (ses) {
+ dhcpv4_packet_ref(pack);
- if (conf_verbose && ses) {
- log_switch(dhcpv4->ctx, &ses->ses);
- log_ppp_info2("recv ");
- dhcpv4_print_packet(pack, log_ppp_info2);
+ if (conf_verbose) {
+ log_switch(dhcpv4->ctx, &ses->ses);
+ log_ppp_info2("recv ");
+ dhcpv4_print_packet(pack, 0, log_ppp_info2);
+ }
}
} else {
log_switch(dhcpv4->ctx, &ses->ses);
if (conf_verbose) {
log_ppp_info2("recv ");
- dhcpv4_print_packet(pack, log_ppp_info2);
+ dhcpv4_print_packet(pack, 0, log_ppp_info2);
}
- if (ses->ses.ipv4 && ses->ses.state == AP_STATE_ACTIVE && pack->request_ip == ses->ses.ipv4->peer_addr)
- dhcpv4_send_reply(DHCPOFFER, dhcpv4, pack, ses->yiaddr, ses->siaddr, ses->mask, conf_lease_time);
-
- dhcpv4_packet_free(pack);
+ if (ses->ses.state == AP_STATE_ACTIVE && pack->request_ip == ses->yiaddr)
+ dhcpv4_send_reply(DHCPOFFER, dhcpv4, pack, ses->yiaddr, ses->siaddr, ses->mask, ses->lease_time, ses->dhcpv4_relay_reply);
}
} else if (pack->msg_type == DHCPREQUEST) {
ses = ipoe_session_lookup(serv, pack);
@@ -686,7 +741,7 @@ static void ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p
if (!ses) {
if (conf_verbose) {
log_info2("recv ");
- dhcpv4_print_packet(pack, log_info2);
+ dhcpv4_print_packet(pack, 0, log_info2);
}
dhcpv4_send_nak(dhcpv4, pack);
@@ -696,52 +751,146 @@ static void ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p
if (conf_verbose) {
log_info2("recv ");
- dhcpv4_print_packet(pack, log_info2);
+ dhcpv4_print_packet(pack, 0, log_info2);
}
- if (pack->server_id == ses->siaddr && pack->request_ip && pack->request_ip != ses->yiaddr)
+ if (pack->server_id == ses->siaddr)
dhcpv4_send_nak(dhcpv4, pack);
+ else if (ses->serv->dhcpv4_relay)
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, pack, 0);
ap_session_terminate(&ses->ses, TERM_USER_REQUEST, 0);
} else {
if (conf_verbose) {
log_switch(dhcpv4->ctx, &ses->ses);
log_ppp_info2("recv ");
- dhcpv4_print_packet(pack, log_ppp_info2);
+ dhcpv4_print_packet(pack, 0, log_ppp_info2);
}
if (serv->opt_shared == 0)
ipoe_drop_sessions(serv, ses);
- if (ses->ses.state == AP_STATE_STARTING && !ses->dhcpv4_request) {
+ if (ses->ses.state == AP_STATE_STARTING && ses->yiaddr && !ses->dhcpv4_request) {
ses->dhcpv4_request = pack;
- pack = NULL;
+ dhcpv4_packet_ref(pack);
triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_activate, ses);
- } else if (ses->ses.state == AP_STATE_ACTIVE && !ses->dhcpv4_request) {
- ses->dhcpv4_request = pack;
- pack = NULL;
- triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_keepalive, ses);
+ } else if (ses->ses.state == AP_STATE_ACTIVE) {
+ dhcpv4_packet_ref(pack);
+ triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_keepalive, pack);
}
}
}
- if (pack)
- dhcpv4_packet_free(pack);
} else if (pack->msg_type == DHCPDECLINE || pack->msg_type == DHCPRELEASE) {
ses = ipoe_session_lookup(serv, pack);
if (ses) {
if (conf_verbose) {
log_switch(dhcpv4->ctx, &ses->ses);
log_ppp_info2("recv ");
- dhcpv4_print_packet(pack, log_ppp_info2);
+ dhcpv4_print_packet(pack, 0, log_ppp_info2);
}
+
+ if (pack->msg_type == DHCPDECLINE && ses->serv->dhcpv4_relay)
+ dhcpv4_relay_send(ses->serv->dhcpv4_relay, pack, 0);
ap_session_terminate(&ses->ses, TERM_USER_REQUEST, 0);
}
+ }
+ pthread_mutex_unlock(&serv->lock);
+}
+
+static int parse_dhcpv4_mask(uint32_t mask)
+{
+ int i;
+
+ for (i = 31; i >= 0 && (mask & (1 << i)); i--);
+
+ return 32 - (i + 1);
+}
+
+static void ipoe_ses_recv_dhcpv4_relay(struct ipoe_session *ses)
+{
+ struct dhcpv4_packet *pack = ses->dhcpv4_relay_reply;
+ struct dhcpv4_option *opt;
+
+ if (conf_verbose) {
+ log_ppp_info2("recv ");
+ dhcpv4_print_packet(pack, 1, log_ppp_info2);
+ }
+
+ if (pack->msg_type == DHCPOFFER && ses->ses.state == AP_STATE_STARTING) {
+ triton_timer_del(&ses->timer);
+
+ ses->relay_server_id = pack->server_id;
+
+ if (!ses->yiaddr) {
+ ses->yiaddr = pack->hdr->yiaddr;
+ ses->relay_addr = 1;
+ }
+
+ if (!ses->siaddr) {
+ opt = dhcpv4_packet_find_opt(pack, 3);
+ if (opt)
+ ses->siaddr = *(in_addr_t *)opt->data;
+ }
+
+ opt = dhcpv4_packet_find_opt(pack, 51);
+ if (opt)
+ ses->lease_time = ntohl(*(uint32_t *)opt->data);
+
+ opt = dhcpv4_packet_find_opt(pack, 1);
+ if (opt)
+ ses->mask = parse_dhcpv4_mask(ntohl(*(uint32_t *)opt->data));
+
+ __ipoe_session_start(ses);
+ } else if (pack->msg_type == DHCPACK) {
+ if (ses->ses.state == AP_STATE_STARTING)
+ __ipoe_session_activate(ses);
+ else
+ dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, ses->yiaddr, ses->siaddr, ses->mask, ses->lease_time, ses->dhcpv4_relay_reply);
+
+ } else if (pack->msg_type == DHCPNAK) {
+ dhcpv4_send_nak(ses->serv->dhcpv4, ses->dhcpv4_request);
+ ap_session_terminate(&ses->ses, TERM_NAS_REQUEST, 0);
+ return;
+ }
+
+ dhcpv4_packet_free(ses->dhcpv4_relay_reply);
+ ses->dhcpv4_relay_reply = NULL;
+}
+
+static void ipoe_recv_dhcpv4_relay(struct dhcpv4_packet *pack)
+{
+ struct ipoe_serv *serv = container_of(triton_context_self(), typeof(*serv), ctx);
+ struct ipoe_session *ses;
+ int found = 0;
+ //struct dhcpv4_packet *reply;
+
+ if (ap_shutdown) {
dhcpv4_packet_free(pack);
+ return;
+ }
+
+ pthread_mutex_lock(&serv->lock);
+ list_for_each_entry(ses, &serv->sessions, entry) {
+ if (ses->xid != pack->hdr->xid)
+ continue;
+ if (memcmp(ses->hwaddr, pack->hdr->chaddr, 6))
+ continue;
+
+ found = 1;
+ break;
}
+
+ if (found && !ses->dhcpv4_relay_reply) {
+ ses->dhcpv4_relay_reply = pack;
+ triton_context_call(&ses->ctx, (triton_event_func)ipoe_ses_recv_dhcpv4_relay, ses);
+ } else
+ dhcpv4_packet_free(pack);
+
pthread_mutex_unlock(&serv->lock);
}
+
static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struct ethhdr *eth, struct iphdr *iph)
{
struct ipoe_session *ses;
@@ -908,7 +1057,7 @@ static void ev_radius_coa(struct ev_radius_t *ev)
}
//if (l4_redirect && !ses->l4_redirect) || (!l4_redirect && ses->l4_redirect))
- if (l4_redirect != ses->l4_redirect)
+ if (l4_redirect != ses->l4_redirect && ev->ses->state == AP_STATE_ACTIVE)
ipoe_change_l4_redirect(ses, l4_redirect);
}
#endif
@@ -927,6 +1076,11 @@ static void ipoe_serv_close(struct triton_context_t *ctx)
if (serv->dhcpv4)
dhcpv4_free(serv->dhcpv4);
+
+ if (serv->dhcpv4_relay) {
+ ipoe_serv_del_addr(serv, serv->dhcpv4_relay->giaddr);
+ dhcpv4_relay_free(serv->dhcpv4_relay, &serv->ctx);
+ }
triton_context_unregister(ctx);
@@ -983,7 +1137,7 @@ struct ipoe_serv *ipoe_find_serv(const char *ifname)
static void add_interface(const char *ifname, int ifindex, const char *opt)
{
- char *str0, *str, *ptr1, *ptr2;
+ char *str0 = NULL, *str, *ptr1, *ptr2;
int end;
struct ipoe_serv *serv;
int opt_shared = conf_shared;
@@ -991,6 +1145,10 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
int opt_up = 0;
int opt_mode = conf_mode;
int opt_ifcfg = conf_ifcfg;
+ const char *opt_relay = conf_relay;
+ const char *opt_giaddr = NULL;
+ in_addr_t relay_addr = 0;
+ in_addr_t giaddr = 0;
str0 = strchr(opt, ',');
if (str0) {
@@ -1033,6 +1191,12 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
goto parse_err;
} else if (strcmp(str, "ifcfg") == 0) {
opt_ifcfg = atoi(ptr1);
+ } else if (strcmp(str, "relay") == 0) {
+ opt_relay = ptr1;
+ relay_addr = inet_addr(ptr1);
+ } else if (strcmp(str, "giaddr") == 0) {
+ opt_giaddr = ptr1;
+ giaddr = inet_addr(ptr1);
}
if (end)
@@ -1040,9 +1204,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
str = ptr2 + 1;
}
-
- _free(str0);
- }
+ }
if (!opt_up && !opt_dhcpv4) {
opt_up = conf_up;
@@ -1074,6 +1236,20 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
serv->opt_mode = opt_mode;
serv->opt_ifcfg = opt_ifcfg;
+ if (serv->dhcpv4_relay &&
+ (serv->dhcpv4_relay->addr != relay_addr || serv->dhcpv4_relay->giaddr != giaddr)) {
+ ipoe_serv_del_addr(serv, serv->dhcpv4_relay->giaddr);
+ dhcpv4_relay_free(serv->dhcpv4_relay, &serv->ctx);
+ serv->dhcpv4_relay = NULL;
+ }
+
+ if (serv->opt_dhcpv4 && opt_relay && opt_giaddr)
+ ipoe_serv_add_addr(serv, serv->dhcpv4_relay->giaddr);
+ serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay);
+
+ if (str0)
+ _free(str0);
+
return;
}
@@ -1098,12 +1274,20 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
serv->dhcpv4 = dhcpv4_create(&serv->ctx, serv->ifname, opt);
if (serv->dhcpv4)
serv->dhcpv4->recv = ipoe_recv_dhcpv4;
+
+ if (opt_relay && opt_giaddr) {
+ ipoe_serv_add_addr(serv, giaddr);
+ serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay);
+ }
}
triton_context_wakeup(&serv->ctx);
list_add_tail(&serv->entry, &serv_list);
+ if (str0)
+ _free(str0);
+
return;
parse_err:
@@ -1274,6 +1458,7 @@ static void parse_conf_rad_attr(const char *opt, int *val)
} else
*val = -1;
}
+
static void load_radius_attrs(void)
{
parse_conf_rad_attr("attr-dhcp-client-ip", &conf_attr_dhcp_client_ip);
@@ -1330,7 +1515,7 @@ static void load_config(void)
if (opt)
conf_lease_time = atoi(opt);
- opt = conf_get_opt("ipoe", "lease-timeout");
+ opt = conf_get_opt("ipoe", "max-lease-time");
if (opt)
conf_lease_timeout = atoi(opt);
@@ -1366,6 +1551,8 @@ static void load_config(void)
log_emerg("ipoe: failed to parse 'mode=%s'\n", opt);
} else
conf_mode = MODE_L2;
+
+ conf_relay = conf_get_opt("ipoe", "relay");
conf_dhcpv4 = 0;
conf_up = 0;
@@ -1403,9 +1590,10 @@ static void ipoe_init(void)
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
#ifdef RADIUS
- if (triton_module_loaded("radius"))
+ /*if (triton_module_loaded("radius")) {
triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept);
triton_event_register_handler(EV_RADIUS_COA, (triton_event_func)ev_radius_coa);
+ }*/
#endif
}