summaryrefslogtreecommitdiff
path: root/accel-pppd/ipv6
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2011-08-28 22:38:22 +0400
committerKozlov Dmitry <xeb@mail.ru>2011-08-28 22:38:22 +0400
commit47c8e0517c037231335cdc1595acf2d53f8c6e22 (patch)
tree4f6dde6159d8904f019e771e445cf93c6aa6bc85 /accel-pppd/ipv6
parent3e9cb77429b07a0317c7f394c22cf5cb78b59136 (diff)
downloadaccel-ppp-47c8e0517c037231335cdc1595acf2d53f8c6e22.tar.gz
accel-ppp-47c8e0517c037231335cdc1595acf2d53f8c6e22.zip
ipv6_dhcp: implemented DNS,DNSSL,IA_PD options
Diffstat (limited to 'accel-pppd/ipv6')
-rw-r--r--accel-pppd/ipv6/dhcpv6.c139
-rw-r--r--accel-pppd/ipv6/dhcpv6.h11
-rw-r--r--accel-pppd/ipv6/dhcpv6_packet.c18
3 files changed, 155 insertions, 13 deletions
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
index c431fbee..edbc225c 100644
--- a/accel-pppd/ipv6/dhcpv6.c
+++ b/accel-pppd/ipv6/dhcpv6.c
@@ -38,7 +38,9 @@ struct dhcpv6_pd
struct ppp_pd_t pd;
struct dhcpv6_opt_clientid *clientid;
struct dhcpv6_opt_serverid serverid;
- uint32_t iaid;
+ uint32_t addr_iaid;
+ uint32_t dp_iaid;
+ struct ipv6db_prefix_t *ipv6_dp;
};
static struct triton_md_handler_t dhcpv6_hnd;
@@ -117,6 +119,9 @@ static void ev_ppp_finished(struct ppp_t *ppp)
if (pd->clientid)
_free(pd->clientid);
+
+ if (pd->ipv6_dp)
+ ipdb_put_ipv6_prefix(ppp, pd->ipv6_dp);
_free(pd);
}
@@ -133,7 +138,6 @@ static void dhcpv6_send(struct dhcpv6_packet *reply)
addr.sin6_scope_id = reply->ppp->ifindex;
sendto(dhcpv6_hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&addr, sizeof(addr));
- printf("sendto: %s %i\n", strerror(errno), errno);
}
static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_addr *addr)
@@ -152,10 +156,11 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
struct dhcpv6_option *opt, *opt1, *opt2, *opt3, *opt4;
struct dhcpv6_opt_ia_na *ia_na;
struct dhcpv6_opt_ia_addr *ia_addr;
+ struct dhcpv6_opt_ia_prefix *ia_prefix;
struct dhcpv6_opt_status *status;
struct ipv6db_addr_t *a;
struct in6_addr addr, *addr_ptr;
- int i, j, f = 0, f1;
+ int i, j, f = 0, f1, f2 = 0;
uint16_t *ptr;
reply = dhcpv6_packet_alloc_reply(req, code);
@@ -163,18 +168,28 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
return;
list_for_each_entry(opt, &req->opt_list, entry) {
+
+ // IA_NA
if (ntohs(opt->hdr->code) == D6_OPTION_IA_NA) {
opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_NA, sizeof(struct dhcpv6_opt_ia_na) - sizeof(struct dhcpv6_opt_hdr));
memcpy(opt1->hdr + 1, opt->hdr + 1, ntohs(opt1->hdr->len));
- if (list_empty(&req->ppp->ipv6->addr_list) || f) {
+
+ ia_na = (struct dhcpv6_opt_ia_na *)opt1->hdr;
+ ia_na->T1 = 0;
+ ia_na->T2 = 0;
+
+ if ((req->hdr->type == D6_RENEW || req->hdr->type == D6_REBIND) && pd->addr_iaid != ia_na->iaid) {
+ opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
+ status = (struct dhcpv6_opt_status *)opt3->hdr;
+ status->code = htons(D6_STATUS_NoBinding);
+ } else if (list_empty(&req->ppp->ipv6->addr_list) || f) {
opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
status = (struct dhcpv6_opt_status *)opt3->hdr;
status->code = htons(D6_STATUS_NoAddrsAvail);
} else {
- if (code == D6_REPLY) {
- ia_na = (struct dhcpv6_opt_ia_na *)opt->hdr;
- pd->iaid = ia_na->iaid;
- }
+
+ if (req->hdr->type == D6_REQUEST)
+ pd->addr_iaid = ia_na->iaid;
f = 1;
@@ -191,6 +206,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
list_for_each_entry(opt2, &opt->opt_list, entry) {
if (ntohs(opt2->hdr->code) == D6_OPTION_IAADDR) {
ia_addr = (struct dhcpv6_opt_ia_addr *)opt2->hdr;
+
f1 = 0;
list_for_each_entry(a, &req->ppp->ipv6->addr_list, entry) {
build_addr(a, req->ppp->ipv6->peer_intf_id, &addr);
@@ -203,19 +219,102 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
if (!f1) {
opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_IAADDR, sizeof(*ia_addr) - sizeof(struct dhcpv6_opt_hdr));
memcpy(opt3->hdr->data, opt2->hdr->data, sizeof(*ia_addr) - sizeof(struct dhcpv6_opt_hdr));
+
+ ia_addr = (struct dhcpv6_opt_ia_addr *)opt3->hdr;
+ ia_addr->pref_lifetime = 0;
+ ia_addr->valid_lifetime = 0;
+
opt4 = dhcpv6_nested_option_alloc(reply, opt3, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
status = (struct dhcpv6_opt_status *)opt4->hdr;
status->code = htons(D6_STATUS_NotOnLink);
}
}
}
+
+ opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
+ status = (struct dhcpv6_opt_status *)opt3->hdr;
+ status->code = htons(D6_STATUS_Success);
}
+
+ // IA_PD
+ } else if (ntohs(opt->hdr->code) == D6_OPTION_IA_PD) {
+ opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_PD, sizeof(struct dhcpv6_opt_ia_na) - sizeof(struct dhcpv6_opt_hdr));
+ memcpy(opt1->hdr + 1, opt->hdr + 1, ntohs(opt1->hdr->len));
+
+ ia_na = (struct dhcpv6_opt_ia_na *)opt1->hdr;
+ ia_na->T1 = 0;
+ ia_na->T2 = 0;
+
+ if (req->hdr->type == D6_SOLICIT && !pd->ipv6_dp)
+ pd->ipv6_dp = ipdb_get_ipv6_prefix(req->ppp);
+
+ if ((req->hdr->type == D6_RENEW || req->hdr->type == D6_REBIND) && pd->dp_iaid != ia_na->iaid) {
+ opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
+ status = (struct dhcpv6_opt_status *)opt3->hdr;
+ status->code = htons(D6_STATUS_NoBinding);
+ } else if (!pd->ipv6_dp || list_empty(&pd->ipv6_dp->prefix_list) || f2) {
+ opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
+ status = (struct dhcpv6_opt_status *)opt3->hdr;
+ status->code = htons(D6_STATUS_NoAddrsAvail);
+ } else {
+
+ if (req->hdr->type == D6_REQUEST)
+ pd->dp_iaid = ia_na->iaid;
+
+ f2 = 1;
+
+ list_for_each_entry(a, &pd->ipv6_dp->prefix_list, entry) {
+ opt2 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_IAPREFIX, sizeof(*ia_prefix) - sizeof(struct dhcpv6_opt_hdr));
+ ia_prefix = (struct dhcpv6_opt_ia_prefix *)opt2->hdr;
+
+ memcpy(&ia_prefix->prefix, &a->addr, sizeof(a->addr));
+ ia_prefix->prefix_len = a->prefix_len;
+ ia_prefix->pref_lifetime = htonl(conf_pref_lifetime);
+ ia_prefix->valid_lifetime = htonl(conf_valid_lifetime);
+ }
+
+ list_for_each_entry(opt2, &opt->opt_list, entry) {
+ if (ntohs(opt2->hdr->code) == D6_OPTION_IAPREFIX) {
+ ia_prefix = (struct dhcpv6_opt_ia_prefix *)opt2->hdr;
+
+ f1 = 0;
+ list_for_each_entry(a, &pd->ipv6_dp->prefix_list, entry) {
+ if (a->prefix_len != ia_prefix->prefix_len)
+ continue;
+ if (memcmp(&a->addr, &ia_prefix->prefix, sizeof(a->addr)))
+ continue;
+ f1 = 1;
+ break;
+ }
+
+ if (!f1) {
+ opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_IAPREFIX, sizeof(*ia_prefix) - sizeof(struct dhcpv6_opt_hdr));
+ memcpy(opt3->hdr->data, opt2->hdr->data, sizeof(*ia_prefix) - sizeof(struct dhcpv6_opt_hdr));
+ ia_prefix = (struct dhcpv6_opt_ia_prefix *)opt3->hdr;
+ ia_prefix->pref_lifetime = 0;
+ ia_prefix->valid_lifetime = 0;
+
+ opt4 = dhcpv6_nested_option_alloc(reply, opt3, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
+ status = (struct dhcpv6_opt_status *)opt4->hdr;
+ status->code = htons(D6_STATUS_NotOnLink);
+ }
+ }
+ }
+
+ opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
+ status = (struct dhcpv6_opt_status *)opt3->hdr;
+ status->code = htons(D6_STATUS_Success);
+ }
+
+ // IA_TA
} else if (ntohs(opt->hdr->code) == D6_OPTION_IA_TA) {
opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_TA, sizeof(struct dhcpv6_opt_ia_ta) - sizeof(struct dhcpv6_opt_hdr));
memcpy(opt1->hdr + 1, opt->hdr + 1, ntohs(opt1->hdr->len));
opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_STATUS_CODE, sizeof(struct dhcpv6_opt_status) - sizeof(struct dhcpv6_opt_hdr));
status = (struct dhcpv6_opt_status *)opt3->hdr;
status->code = htons(D6_STATUS_NoAddrsAvail);
+
+ // Option Request
} else if (ntohs(opt->hdr->code) == D6_OPTION_ORO) {
for (i = ntohs(opt->hdr->len) / 2, ptr = (uint16_t *)opt->hdr->data; i; i--, ptr++) {
if (ntohs(*ptr) == D6_OPTION_DNS_SERVERS) {
@@ -302,14 +401,34 @@ static void dhcpv6_recv_request(struct dhcpv6_packet *req)
dhcpv6_send_reply(req, pd, D6_REPLY);
}
-static void dhcpv6_recv_renew(struct dhcpv6_packet *pkt)
+static void dhcpv6_recv_renew(struct dhcpv6_packet *req)
{
+ struct dhcpv6_pd *pd = find_pd(req->ppp);
+ if (!pd)
+ return;
+
+ if (!req->clientid) {
+ log_ppp_error("dhcpv6: no Client-ID option\n");
+ return;
+ }
+
+ if (!req->serverid) {
+ log_ppp_error("dhcpv6: no Server-ID option\n");
+ return;
+ }
+
+ if (!pd->clientid) {
+ log_ppp_error("dhcpv6: no Solicit or Request was received\n");
+ return;
+ }
+
+ dhcpv6_send_reply(req, pd, D6_REPLY);
}
static void dhcpv6_recv_rebind(struct dhcpv6_packet *pkt)
{
-
+ dhcpv6_recv_renew(pkt);
}
static void dhcpv6_recv_release(struct dhcpv6_packet *pkt)
diff --git a/accel-pppd/ipv6/dhcpv6.h b/accel-pppd/ipv6/dhcpv6.h
index 6c5d164c..c584eda1 100644
--- a/accel-pppd/ipv6/dhcpv6.h
+++ b/accel-pppd/ipv6/dhcpv6.h
@@ -32,6 +32,8 @@
#define D6_OPTION_RECONF_ACCEPT 20
#define D6_OPTION_DNS_SERVERS 23
#define D6_OPTION_DOMAIN_LIST 24
+#define D6_OPTION_IA_PD 25
+#define D6_OPTION_IAPREFIX 26
#define D6_SOLICIT 1
#define D6_ADVERTISE 2
@@ -141,6 +143,15 @@ struct dhcpv6_opt_status
char msg[0];
} __packed;
+struct dhcpv6_opt_ia_prefix
+{
+ struct dhcpv6_opt_hdr hdr;
+ uint32_t pref_lifetime;
+ uint32_t valid_lifetime;
+ uint8_t prefix_len;
+ struct in6_addr prefix;
+} __packed;
+
struct dhcpv6_option
{
diff --git a/accel-pppd/ipv6/dhcpv6_packet.c b/accel-pppd/ipv6/dhcpv6_packet.c
index 9a709963..e0e348d4 100644
--- a/accel-pppd/ipv6/dhcpv6_packet.c
+++ b/accel-pppd/ipv6/dhcpv6_packet.c
@@ -30,6 +30,7 @@ static void print_status(struct dhcpv6_option *opt, void (*print)(const char *fm
static void print_uint64(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...));
static void print_reconf(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...));
static void print_dnssl(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...));
+static void print_ia_prefix(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...));
static struct dict_option known_options[] = {
{ D6_OPTION_CLIENTID, "Client-ID", 1, 0, print_clientid },
@@ -53,6 +54,8 @@ static struct dict_option known_options[] = {
{ D6_OPTION_RECONF_ACCEPT, "Reconfigure-Accept", 1, 0 },
{ D6_OPTION_DNS_SERVERS, "DNS", 1, 0, print_ipv6addr_array },
{ D6_OPTION_DOMAIN_LIST, "DNSSL", 1, 0, print_dnssl },
+ { D6_OPTION_IA_PD, "IA-PD", 1, sizeof(struct dhcpv6_opt_ia_na), print_ia_na },
+ { D6_OPTION_IAPREFIX, "IA-Prefix", 1, sizeof(struct dhcpv6_opt_ia_prefix), print_ia_prefix },
{ 0 }
};
@@ -337,7 +340,7 @@ static void print_ia_ta(struct dhcpv6_option *opt, void (*print)(const char *fmt
static void print_ia_addr(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...))
{
struct dhcpv6_opt_ia_addr *o = (struct dhcpv6_opt_ia_addr *)opt->hdr;
- char str[50];
+ char str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &o->addr, str, sizeof(str));
print(" %s pref_lifetime=%i valid_lifetime=%i", str, ntohl(o->pref_lifetime), ntohl(o->valid_lifetime));
@@ -382,7 +385,7 @@ static void print_time(struct dhcpv6_option *opt, void (*print)(const char *fmt,
static void print_ipv6addr(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...))
{
- char str[50];
+ char str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, opt->hdr->data, str, sizeof(str));
@@ -391,7 +394,7 @@ static void print_ipv6addr(struct dhcpv6_option *opt, void (*print)(const char *
static void print_ipv6addr_array(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...))
{
- char str[50];
+ char str[INET6_ADDRSTRLEN];
int i;
int f = 0;
struct in6_addr *addr = (struct in6_addr *)opt->hdr->data;
@@ -436,3 +439,12 @@ static void print_dnssl(struct dhcpv6_option *opt, void (*print)(const char *fmt
}
+static void print_ia_prefix(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...))
+{
+ struct dhcpv6_opt_ia_prefix *o = (struct dhcpv6_opt_ia_prefix *)opt->hdr;
+ char str[INET6_ADDRSTRLEN];
+
+ inet_ntop(AF_INET6, &o->prefix, str, sizeof(str));
+ print(" %s/%i pref_lifetime=%i valid_lifetime=%i", str, o->prefix_len, ntohl(o->pref_lifetime), ntohl(o->valid_lifetime));
+}
+