]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add RELEASE support to DHCPv6
authorRoy Marples <roy@marples.name>
Thu, 4 Apr 2013 21:59:02 +0000 (21:59 +0000)
committerRoy Marples <roy@marples.name>
Thu, 4 Apr 2013 21:59:02 +0000 (21:59 +0000)
dhcp6.c
dhcp6.h

diff --git a/dhcp6.c b/dhcp6.c
index e5a384f7f2e5d3000d90404f634520a88a3058b1..aabd53de0c17833ead38d510fd2182a8599ba2ef 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -92,6 +92,7 @@ static const struct dhcp6_op dhcp6_ops[] = {
        { DHCP6_REBIND, "REBIND6" },
        { DHCP6_CONFIRM, "CONFIRM6" },
        { DHCP6_INFORMATION_REQ, "INFORM6" },
+       { DHCP6_RELEASE, "RELEASE6" },
        { 0, NULL }
 };
 
@@ -373,15 +374,17 @@ dhcp6_makemessage(struct interface *ifp)
        ifo = ifp->options;
        len = 0;
        si = NULL;
-       for (opt = dhcp6_opts; opt->option; opt++) {
-               if (!(opt->type & REQUEST ||
-                   has_option_mask(ifo->requestmask6, opt->option)))
-                       continue;
-               len += sizeof(*u16);
+       if (state->state != DH6S_RELEASE) {
+               for (opt = dhcp6_opts; opt->option; opt++) {
+                       if (!(opt->type & REQUEST ||
+                           has_option_mask(ifo->requestmask6, opt->option)))
+                               continue;
+                       len += sizeof(*u16);
+               }
+               if (len == 0)
+                       len = sizeof(*u16) * 2;
+               len += sizeof(*o);
        }
-       if (len == 0)
-               len = sizeof(*u16) * 2;
-       len += sizeof(*o);
 
        len += sizeof(*state->send);
        len += sizeof(*o) + 14; /* clientid */
@@ -398,6 +401,8 @@ dhcp6_makemessage(struct interface *ifp)
                m = state->recv;
                ml = state->recv_len;
                /* FALLTHROUGH */
+       case DH6S_RELEASE:
+               /* FALLTHROUGH */
        case DH6S_RENEW:
                if (m == NULL) {
                        m = state->new;
@@ -463,6 +468,9 @@ dhcp6_makemessage(struct interface *ifp)
        case DH6S_INFORM:
                state->send->type = DHCP6_INFORMATION_REQ;
                break;
+       case DH6S_RELEASE:
+               state->send->type = DHCP6_RELEASE;
+               break;
        default:
                errno = EINVAL;
                free(state->send);
@@ -550,23 +558,25 @@ dhcp6_makemessage(struct interface *ifp)
                }
        }
 
-       o = D6_NEXT_OPTION(o);
-       o->code = htons(D6_OPTION_ORO);
-       o->len = 0;
-       u16 = (uint16_t *)(void *)D6_OPTION_DATA(o);
-       for (opt = dhcp6_opts; opt->option; opt++) {
-               if (!(opt->type & REQUEST ||
-                   has_option_mask(ifo->requestmask6, opt->option)))
-                       continue;
-               *u16++ = htons(opt->option);
-               o->len += sizeof(*u16);
-       }
-       if (o->len == 0) {
-               *u16++ = htons(D6_OPTION_DNS_SERVERS);
-               *u16++ = htons(D6_OPTION_DOMAIN_LIST);
-               o->len = sizeof(*u16) * 2;
+       if (state->send->type !=  DHCP6_RELEASE) {
+               o = D6_NEXT_OPTION(o);
+               o->code = htons(D6_OPTION_ORO);
+               o->len = 0;
+               u16 = (uint16_t *)(void *)D6_OPTION_DATA(o);
+               for (opt = dhcp6_opts; opt->option; opt++) {
+                       if (!(opt->type & REQUEST ||
+                           has_option_mask(ifo->requestmask6, opt->option)))
+                               continue;
+                       *u16++ = htons(opt->option);
+                       o->len += sizeof(*u16);
+               }
+               if (o->len == 0) {
+                       *u16++ = htons(D6_OPTION_DNS_SERVERS);
+                       *u16++ = htons(D6_OPTION_DOMAIN_LIST);
+                       o->len = sizeof(*u16) * 2;
+               }
+               o->len = htons(o->len);
        }
-       o->len = htons(o->len);
 
        return 0;
 }
@@ -758,6 +768,15 @@ dhcp6_sendconfirm(void *arg)
        dhcp6_sendmessage(arg, dhcp6_sendconfirm);
 }
 
+/*
+static void
+dhcp6_sendrelease(void *arg)
+{
+
+       dhcp6_sendmessage(arg, dhcp6_sendrelease);
+}
+*/
+
 static void
 dhcp6_startrenew(void *arg)
 {
@@ -942,6 +961,30 @@ dhcp6_startexpire(void *arg)
        dhcp6_startdiscover(ifp);
 }
 
+static void
+dhcp6_startrelease(struct interface *ifp)
+{
+       struct dhcp6_state *state;
+
+       state = D6_STATE(ifp);
+       state->state = DH6S_RELEASE;
+       state->start_uptime = uptime();
+       state->RTC = 0;
+       state->IRT = REL_TIMEOUT;
+       state->MRT = 0;
+       state->MRC = REL_MAX_RC;
+       //state->MRCcallback = dhcp6_failrelease;
+       state->MRCcallback = NULL;
+
+       if (dhcp6_makemessage(ifp) == -1)
+               syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
+       else
+               /* XXX: We should loop a few times
+                * Luckily RFC3315 section 18.1.6 says this is optional */
+               //dhcp6_sendrelease(ifp);
+               dhcp6_sendmessage(ifp, NULL);
+}
+
 static int dhcp6_getstatus(const struct dhcp6_option *o)
 {
        const struct dhcp6_status *s;
@@ -1877,6 +1920,10 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
        eloop_timeout_delete(NULL, ifp);
        state = D6_STATE(ifp);
        if (state) {
+               if (ifp->options->options & DHCPCD_RELEASE) {
+                       dhcp6_startrelease(ifp);
+                       unlink(state->leasefile);
+               }
                dhcp6_freedrop_addrs(ifp, drop);
                if (drop && state->new) {
                        if (reason == NULL)
diff --git a/dhcp6.h b/dhcp6.h
index 217c4cd2a797e072a63e7534b602d676fd74a414..921dc7a24d013aface1191732e57c7cecc95dd60 100644 (file)
--- a/dhcp6.h
+++ b/dhcp6.h
@@ -135,7 +135,7 @@ struct dhcp6_status {
 
 #define DHCP6_RAND_MIN         -100
 #define DHCP6_RAND_MAX         100
+
 enum DH6S {
        DH6S_INIT,
        DH6S_DISCOVER,
@@ -147,7 +147,8 @@ enum DH6S {
        DH6S_INFORM,
        DH6S_RENEW_REQUESTED,
        DH6S_PROBE,
-       DH6S_DELEGATED
+       DH6S_DELEGATED,
+       DH6S_RELEASE
 };
 
 struct dhcp6_state {