summaryrefslogtreecommitdiff
path: root/accel-pppd/ipv6
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2014-07-24 22:11:33 +0400
committerDmitry Kozlov <xeb@mail.ru>2014-07-24 22:11:33 +0400
commit768ad4d4f1930ffe1630e82789cd58191b651a64 (patch)
tree7db7adff9a766e5f936d9a7e68aebe5edea92d0b /accel-pppd/ipv6
parentcddc20689a17a1b30d491cd2021f911a669f6dbc (diff)
downloadaccel-ppp-xebd-768ad4d4f1930ffe1630e82789cd58191b651a64.tar.gz
accel-ppp-xebd-768ad4d4f1930ffe1630e82789cd58191b651a64.zip
radius: exit from active interim request when termination event occures
Diffstat (limited to 'accel-pppd/ipv6')
-rw-r--r--accel-pppd/ipv6/dhcpv6.c189
-rw-r--r--accel-pppd/ipv6/dhcpv6.h44
-rw-r--r--accel-pppd/ipv6/nd.c32
3 files changed, 101 insertions, 164 deletions
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
index 809496e..67b1b75 100644
--- a/accel-pppd/ipv6/dhcpv6.c
+++ b/accel-pppd/ipv6/dhcpv6.c
@@ -40,9 +40,10 @@ static int conf_dns_count;
static void *conf_dnssl;
static int conf_dnssl_size;
-struct dhcpv6_pd
-{
+struct dhcpv6_pd {
struct ap_private pd;
+ struct ap_session *ses;
+ struct triton_md_handler_t hnd;
struct dhcpv6_opt_clientid *clientid;
uint32_t addr_iaid;
uint32_t dp_iaid;
@@ -50,35 +51,71 @@ struct dhcpv6_pd
int dp_active:1;
};
-static struct triton_md_handler_t dhcpv6_hnd;
-static struct triton_context_t dhcpv6_ctx;
-
-static uint8_t *buf;
static void *pd_key;
-static void ev_ppp_started(struct ap_session *ses)
+static int dhcpv6_read(struct triton_md_handler_t *h);
+
+static void ev_ses_started(struct ap_session *ses)
{
struct ipv6_mreq mreq;
struct dhcpv6_pd *pd;
+ struct sockaddr_in6 addr;
+ int sock;
+ int f = 1;
if (!ses->ipv6)
return;
+
+ sock = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (!sock) {
+ log_ppp_error("dhcpv6: socket: %s\n", strerror(errno));
+ return;
+ }
+
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f));
- pd = _malloc(sizeof(*pd));
- memset(pd, 0, sizeof(*pd));
+ if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
+ log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno));
+ close(sock);
+ return;
+ }
- pd->pd.key = &pd_key;
- list_add_tail(&pd->pd.entry, &ses->pd_list);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(DHCPV6_SERV_PORT);
+
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
+ log_ppp_error("dhcpv6: bind: %s\n", strerror(errno));
+ close(sock);
+ return;
+ }
memset(&mreq, 0, sizeof(mreq));
mreq.ipv6mr_interface = ses->ifindex;
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xff020000);
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x010002);
- if (setsockopt(dhcpv6_hnd.fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
+ if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
log_ppp_error("dhcpv6: failed to join to All_DHCP_Relay_Agents_and_Servers\n");
+ close(sock);
return;
}
+
+ fcntl(sock, F_SETFL, O_NONBLOCK);
+ fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
+
+ pd = _malloc(sizeof(*pd));
+ memset(pd, 0, sizeof(*pd));
+
+ pd->pd.key = &pd_key;
+ list_add_tail(&pd->pd.entry, &ses->pd_list);
+
+ pd->ses = ses;
+
+ pd->hnd.fd = sock;
+ pd->hnd.read = dhcpv6_read;
+ triton_md_register_handler(ses->ctrl->ctx, &pd->hnd);
+ triton_md_enable_handler(&pd->hnd, MD_MODE_READ);
}
static struct dhcpv6_pd *find_pd(struct ap_session *ses)
@@ -93,7 +130,7 @@ static struct dhcpv6_pd *find_pd(struct ap_session *ses)
return NULL;
}
-static void ev_ppp_finished(struct ap_session *ses)
+static void ev_ses_finished(struct ap_session *ses)
{
struct dhcpv6_pd *pd = find_pd(ses);
@@ -107,24 +144,12 @@ static void ev_ppp_finished(struct ap_session *ses)
if (pd->ipv6_dp)
ipdb_put_ipv6_prefix(ses, pd->ipv6_dp);
+
+ triton_md_unregister_handler(&pd->hnd, 1);
_free(pd);
}
-static void dhcpv6_send(struct dhcpv6_packet *reply)
-{
- struct sockaddr_in6 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons(DHCPV6_CLIENT_PORT);
- addr.sin6_addr.s6_addr32[0] = htons(0xfe80);
- *(uint64_t *)(addr.sin6_addr.s6_addr + 8) = reply->ses->ipv6->peer_intf_id;
- addr.sin6_scope_id = reply->ses->ifindex;
-
- sendto(dhcpv6_hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&addr, sizeof(addr));
-}
-
static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_addr *addr)
{
memcpy(addr, &a->addr, sizeof(*addr));
@@ -405,7 +430,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
dhcpv6_packet_print(reply, log_ppp_info2);
}
- dhcpv6_send(reply);
+ sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
dhcpv6_packet_free(reply);
}
@@ -551,7 +576,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd,
dhcpv6_packet_print(reply, log_ppp_info2);
}
- dhcpv6_send(reply);
+ sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
dhcpv6_packet_free(reply);
}
@@ -559,11 +584,8 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd,
static void dhcpv6_recv_solicit(struct dhcpv6_packet *req)
{
- struct dhcpv6_pd *pd = find_pd(req->ses);
+ struct dhcpv6_pd *pd = req->pd;
- if (!pd)
- return;
-
if (!req->clientid) {
log_ppp_error("dhcpv6: no Client-ID option\n");
return;
@@ -591,11 +613,8 @@ static void dhcpv6_recv_solicit(struct dhcpv6_packet *req)
static void dhcpv6_recv_request(struct dhcpv6_packet *req)
{
- struct dhcpv6_pd *pd = find_pd(req->ses);
+ struct dhcpv6_pd *pd = req->pd;
- if (!pd)
- return;
-
if (!req->clientid) {
log_ppp_error("dhcpv6: no Client-ID option\n");
return;
@@ -619,11 +638,8 @@ static void dhcpv6_recv_request(struct dhcpv6_packet *req)
static void dhcpv6_recv_renew(struct dhcpv6_packet *req)
{
- struct dhcpv6_pd *pd = find_pd(req->ses);
+ struct dhcpv6_pd *pd = req->pd;
- if (!pd)
- return;
-
if (!req->clientid) {
log_ppp_error("dhcpv6: no Client-ID option\n");
return;
@@ -656,7 +672,7 @@ static void dhcpv6_recv_renew(struct dhcpv6_packet *req)
static void dhcpv6_recv_information_request(struct dhcpv6_packet *req)
{
- struct dhcpv6_pd *pd = find_pd(req->ses);
+ struct dhcpv6_pd *pd = req->pd;
if (req->rapid_commit) {
log_ppp_error("dhcpv6: unexpected Rapid-Commit option\n");
@@ -670,11 +686,8 @@ static void dhcpv6_recv_information_request(struct dhcpv6_packet *req)
static void dhcpv6_recv_rebind(struct dhcpv6_packet *req)
{
- struct dhcpv6_pd *pd = find_pd(req->ses);
+ struct dhcpv6_pd *pd = req->pd;
- if (!pd)
- return;
-
if (!req->clientid) {
log_ppp_error("dhcpv6: no Client-ID option\n");
return;
@@ -744,18 +757,21 @@ static void dhcpv6_recv_packet(struct dhcpv6_packet *pkt)
static int dhcpv6_read(struct triton_md_handler_t *h)
{
+ struct dhcpv6_pd *pd = container_of(h, typeof(*pd), hnd);
+ struct ap_session *ses = pd->ses;
int n;
struct sockaddr_in6 addr;
socklen_t len = sizeof(addr);
struct dhcpv6_packet *pkt;
- struct ap_session *ses;
+ uint8_t *buf = _malloc(BUF_SIZE);
while (1) {
n = recvfrom(h->fd, buf, BUF_SIZE, 0, &addr, &len);
if (n == -1) {
if (errno == EAGAIN)
- return 0;
+ break;
log_error("dhcpv6: read: %s\n", strerror(errno));
+ continue;
}
if (!IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr))
@@ -769,45 +785,18 @@ static int dhcpv6_read(struct triton_md_handler_t *h)
continue;
}
- pthread_rwlock_rdlock(&ses_lock);
- list_for_each_entry(ses, &ses_list, entry) {
- if (ses->state != AP_STATE_ACTIVE)
- continue;
+ pkt->ses = ses;
+ pkt->pd = pd;
+ pkt->addr = addr;
- if (!ses->ipv6)
- continue;
-
- if (ses->ifindex != addr.sin6_scope_id)
- continue;
-
- if (ses->ipv6->peer_intf_id != *(uint64_t *)(addr.sin6_addr.s6_addr + 8))
- continue;
-
- pkt->ses = ses;
-
- triton_context_call(ses->ctrl->ctx, (triton_event_func)dhcpv6_recv_packet, pkt);
- break;
- }
- pthread_rwlock_unlock(&ses_lock);
+ dhcpv6_recv_packet(pkt);
}
- return 0;
-}
+ _free(buf);
-static void dhcpv6_close(struct triton_context_t *ctx)
-{
- triton_md_unregister_handler(&dhcpv6_hnd, 1);
- triton_context_unregister(ctx);
+ return 0;
}
-static struct triton_md_handler_t dhcpv6_hnd = {
- .read = dhcpv6_read,
-};
-
-static struct triton_context_t dhcpv6_ctx = {
- .close = dhcpv6_close,
-};
-
static void add_dnssl(const char *val)
{
int n = strlen(val);
@@ -951,48 +940,14 @@ static void load_config(void)
static void init(void)
{
- struct sockaddr_in6 addr;
- int sock;
- int f = 1;
-
if (!triton_module_loaded("ipv6_nd"))
log_warn("dhcpv6: ipv6_nd module is not loaded, you probably get misconfigured network environment\n");
load_config();
- sock = socket(AF_INET6, SOCK_DGRAM, 0);
- if (!sock) {
- log_error("dhcpv6: socket: %s\n", strerror(errno));
- return;
- }
-
- fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons(DHCPV6_SERV_PORT);
-
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
- log_error("dhcpv6: bind: %s\n", strerror(errno));
- close(sock);
- return;
- }
-
- fcntl(sock, F_SETFL, O_NONBLOCK);
-
- dhcpv6_hnd.fd = sock;
-
- buf = malloc(BUF_SIZE);
-
- triton_context_register(&dhcpv6_ctx, NULL);
- triton_md_register_handler(&dhcpv6_ctx, &dhcpv6_hnd);
- triton_md_enable_handler(&dhcpv6_hnd, MD_MODE_READ);
- triton_context_wakeup(&dhcpv6_ctx);
-
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
- triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ev_ppp_started);
- triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ev_ppp_finished);
+ triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ev_ses_started);
+ triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ev_ses_finished);
}
DEFINE_INIT(10, init);
diff --git a/accel-pppd/ipv6/dhcpv6.h b/accel-pppd/ipv6/dhcpv6.h
index 4afb5fa..82e366e 100644
--- a/accel-pppd/ipv6/dhcpv6.h
+++ b/accel-pppd/ipv6/dhcpv6.h
@@ -61,22 +61,19 @@
#define DUID_EN 2
#define DUID_LL 3
-struct dhcpv6_opt_hdr
-{
+struct dhcpv6_opt_hdr {
uint16_t code;
uint16_t len;
uint8_t data[0];
} __packed;
-struct dhcpv6_msg_hdr
-{
+struct dhcpv6_msg_hdr {
uint32_t type:8;
uint32_t trans_id:24;
uint8_t data[0];
} __packed;
-struct dhcpv6_duid
-{
+struct dhcpv6_duid {
uint16_t type;
union {
struct {
@@ -96,56 +93,48 @@ struct dhcpv6_duid
} u;
} __packed;
-struct dhcpv6_opt_clientid
-{
+struct dhcpv6_opt_clientid {
struct dhcpv6_opt_hdr hdr;
struct dhcpv6_duid duid;
} __packed;
-struct dhcpv6_opt_serverid
-{
+struct dhcpv6_opt_serverid {
struct dhcpv6_opt_hdr hdr;
struct dhcpv6_duid duid;
} __packed;
-struct dhcpv6_opt_ia_na
-{
+struct dhcpv6_opt_ia_na {
struct dhcpv6_opt_hdr hdr;
uint32_t iaid;
uint32_t T1;
uint32_t T2;
} __packed;
-struct dhcpv6_opt_ia_ta
-{
+struct dhcpv6_opt_ia_ta {
struct dhcpv6_opt_hdr hdr;
uint32_t iaid;
} __packed;
-struct dhcpv6_opt_ia_addr
-{
+struct dhcpv6_opt_ia_addr {
struct dhcpv6_opt_hdr hdr;
struct in6_addr addr;
uint32_t pref_lifetime;
uint32_t valid_lifetime;
} __packed;
-struct dhcpv6_opt_oro
-{
+struct dhcpv6_opt_oro {
struct dhcpv6_opt_hdr hdr;
uint16_t opt[0];
} __packed;
-struct dhcpv6_opt_status
-{
+struct dhcpv6_opt_status {
struct dhcpv6_opt_hdr hdr;
uint16_t code;
char msg[0];
} __packed;
-struct dhcpv6_opt_ia_prefix
-{
+struct dhcpv6_opt_ia_prefix {
struct dhcpv6_opt_hdr hdr;
uint32_t pref_lifetime;
uint32_t valid_lifetime;
@@ -154,8 +143,7 @@ struct dhcpv6_opt_ia_prefix
} __packed;
-struct dhcpv6_option
-{
+struct dhcpv6_option {
struct list_head entry;
struct dhcpv6_opt_hdr *hdr;
@@ -164,10 +152,12 @@ struct dhcpv6_option
struct list_head opt_list;
};
-struct ppp_t;
-struct dhcpv6_packet
-{
+struct dhcpv6_pd;
+
+struct dhcpv6_packet {
struct ap_session *ses;
+ struct dhcpv6_pd *pd;
+ struct sockaddr_in6 addr;
struct dhcpv6_msg_hdr *hdr;
struct dhcpv6_opt_clientid *clientid;
diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c
index 67a4a0f..669840a 100644
--- a/accel-pppd/ipv6/nd.c
+++ b/accel-pppd/ipv6/nd.c
@@ -256,7 +256,6 @@ static int ipv6_nd_start(struct ap_session *ses)
{
int sock;
struct icmp6_filter filter;
- struct sockaddr_in6 addr;
struct ipv6_mreq mreq;
int val;
struct ipv6_nd_handler_t *h;
@@ -268,17 +267,9 @@ static int ipv6_nd_start(struct ap_session *ses)
return -1;
}
- fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
-
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_addr.s6_addr32[0] = htons(0xfe80);
- *(uint64_t *)(addr.sin6_addr.s6_addr + 8) = ses->ipv6->intf_id;
- addr.sin6_scope_id = ses->ifindex;
-
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
- close(sock);
- return 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
+ log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno));
+ goto out_err;
}
val = 2;
@@ -322,6 +313,7 @@ static int ipv6_nd_start(struct ap_session *ses)
goto out_err;
}
+ fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
fcntl(sock, F_SETFL, O_NONBLOCK);
h = _malloc(sizeof(*h));
@@ -358,19 +350,19 @@ static struct ipv6_nd_handler_t *find_pd(struct ap_session *ses)
return NULL;
}
-static void ipv6_nd_start_later(struct ap_session *ses)
-{
- while (ipv6_nd_start(ses) == 1)
- sched_yield();
-}
-
static void ev_ses_started(struct ap_session *ses)
{
+ struct ipv6db_addr_t *a;
+
if (!ses->ipv6)
return;
- if (ipv6_nd_start(ses) == 1)
- triton_context_call(triton_context_self(), (triton_event_func)ipv6_nd_start_later, ses);
+ list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
+ if (a->prefix_len == 64) {
+ ipv6_nd_start(ses);
+ break;
+ }
+ }
}
static void ev_ses_finishing(struct ap_session *ses)