diff options
author | Thomas Markwalder <tmark@isc.org> | 2017-12-07 07:02:06 -0500 |
---|---|---|
committer | Thomas Markwalder <tmark@isc.org> | 2017-12-07 07:02:06 -0500 |
commit | 59336f8007988c2e77999da06de5dfd922dcec97 (patch) | |
tree | 53fe122a8743b7718a5c1d7efa97857929769eb7 /server | |
parent | b4e157d82c161a3697011d64e840d4d5aeb3183d (diff) | |
download | isc-dhcp-59336f8007988c2e77999da06de5dfd922dcec97.tar.gz |
[master] Server(v6) releases pre-existing leases when client roams to new network
Merges in rt44576.
Diffstat (limited to 'server')
-rw-r--r-- | server/dhcpv6.c | 94 |
1 files changed, 82 insertions, 12 deletions
diff --git a/server/dhcpv6.c b/server/dhcpv6.c index cc4b17d6..a45e4025 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -176,6 +176,9 @@ static isc_result_t get_first_ia_addr_val (struct packet* packet, int addr_type, static void set_reply_tee_times(struct reply_state* reply, unsigned ia_cursor); +static const char *iasubopt_plen_str(struct iasubopt *lease); +static int release_on_roam(struct reply_state *reply); + #ifdef DHCP4o6 /* * \brief Omapi I/O handler @@ -2320,10 +2323,13 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) { /* Remove any old ia from the hash. */ if (reply->old_ia != NULL) { - ia_id = &reply->old_ia->iaid_duid; - ia_hash_delete(ia_na_active, - (unsigned char *)ia_id->data, - ia_id->len, MDL); + if (!release_on_roam(reply)) { + ia_id = &reply->old_ia->iaid_duid; + ia_hash_delete(ia_na_active, + (unsigned char *)ia_id->data, + ia_id->len, MDL); + } + ia_dereference(&reply->old_ia, MDL); } @@ -3067,10 +3073,13 @@ reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) { /* Remove any old ia from the hash. */ if (reply->old_ia != NULL) { - ia_id = &reply->old_ia->iaid_duid; - ia_hash_delete(ia_ta_active, - (unsigned char *)ia_id->data, - ia_id->len, MDL); + if (!release_on_roam(reply)) { + ia_id = &reply->old_ia->iaid_duid; + ia_hash_delete(ia_ta_active, + (unsigned char *)ia_id->data, + ia_id->len, MDL); + } + ia_dereference(&reply->old_ia, MDL); } @@ -4113,10 +4122,13 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) { /* Remove any old ia from the hash. */ if (reply->old_ia != NULL) { - ia_id = &reply->old_ia->iaid_duid; - ia_hash_delete(ia_pd_active, - (unsigned char *)ia_id->data, - ia_id->len, MDL); + if (!release_on_roam(reply)) { + ia_id = &reply->old_ia->iaid_duid; + ia_hash_delete(ia_pd_active, + (unsigned char *)ia_id->data, + ia_id->len, MDL); + } + ia_dereference(&reply->old_ia, MDL); } @@ -8147,5 +8159,63 @@ set_reply_tee_times(struct reply_state* reply, unsigned ia_cursor) putULong(reply->buf.data + ia_cursor + 12, reply->rebind); } +/* + * Releases the iasubopts in the pre-existing IA, if they are not in + * the same shared-network as the new IA. + * + * returns 1 if the release was done, 0 otherwise + */ +int +release_on_roam(struct reply_state* reply) { + struct ia_xx* old_ia = reply->old_ia; + struct iasubopt *lease = NULL; + int i; + + if (old_ia == NULL || old_ia->num_iasubopt <= 0) { + return(0); + } + + /* If the old shared-network and new are the same, client hasn't + * roamed, nothing to do. We only check the first one because you + * cannot have iasubopts on different shared-networks within a + * single ia. */ + lease = old_ia->iasubopt[0]; + if (lease->ipv6_pool->shared_network == reply->shared) { + return (0); + } + + /* Old and new are on different shared networks so the client must + * roamed. Release the old leases. */ + for (i = 0; i < old_ia->num_iasubopt; i++) { + lease = old_ia->iasubopt[i]; + + log_info("Client: %s roamed to new network," + " releasing lease: %s%s", + print_hex_1(reply->client_id.len, + reply->client_id.data, 60), + pin6_addr(&lease->addr), iasubopt_plen_str(lease)); + + release_lease6(lease->ipv6_pool, lease); + lease->ia->cltt = cur_time; + write_ia(lease->ia); + } + + return (1); +} + +/* + * Convenience function which returns a string (static buffer) + * containing either a "/" followed by the prefix length or an + * empty string depending on the lease type + */ +const char *iasubopt_plen_str(struct iasubopt *lease) { + static char prefix_buf[16]; + *prefix_buf = 0; + if ((lease->ia) && (lease->ia->ia_type == D6O_IA_PD)) { + sprintf(prefix_buf, "/%-d", lease->plen); + } + + return (prefix_buf); +} #endif /* DHCPv6 */ |