const char *file, int line);
void ia_na_remove_iaaddr(struct ia_na *ia_na, struct iaaddr *iaaddr,
const char *file, int line);
+isc_boolean_t ia_na_equal(const struct ia_na *a, const struct ia_na *b);
isc_result_t ipv6_pool_allocate(struct ipv6_pool **pool,
const struct in6_addr *start_addr, int bits,
reply.cursor = 0;
}
-/* Process a client-supplied IA_NA. This may append options ot the tail of
+/* Process a client-supplied IA_NA. This may append options to the tail of
* the reply packet being built in the reply_state structure.
*/
static isc_result_t
struct option_state *packet_ia;
struct option_cache *oc;
struct data_string ia_data, data;
+ isc_boolean_t lease_in_database;
/* Initialize values that will get cleaned up on return. */
packet_ia = NULL;
memset(&ia_data, 0, sizeof(ia_data));
memset(&data, 0, sizeof(data));
- /* Note that find_client_address() may set reply->lease. */
+ lease_in_database = ISC_FALSE;
+ /*
+ * Note that find_client_address() may set reply->lease.
+ */
/* Make sure there is at least room for the header. */
if ((reply->cursor + IA_NA_OFFSET + 4) > sizeof(reply->buf)) {
* pool timers for each (if any).
*/
if ((status != ISC_R_CANCELED) && !reply->static_lease &&
- (reply->packet->dhcpv6_msg_type != DHCPV6_SOLICIT) &&
+ (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
(reply->ia_na->num_iaaddr != 0)) {
struct iaaddr *tmp;
struct data_string *ia_id;
ia_id->len, reply->ia_na, MDL);
write_ia_na(reply->ia_na);
+
+ /*
+ * Note that we wrote the lease into the database,
+ * so that we know not to release it when we're done
+ * with this function.
+ */
+ lease_in_database = ISC_TRUE;
+
+ /*
+ * If this is a soft binding, we will check to see if we are
+ * suggesting the existing database entry to the client.
+ */
+ } else if ((status != ISC_R_CANCELED) && !reply->static_lease &&
+ (reply->old_ia != NULL)) {
+ if (ia_na_equal(reply->old_ia, reply->ia_na)) {
+ lease_in_database = ISC_TRUE;
+ }
}
cleanup:
ia_na_dereference(&reply->ia_na, MDL);
if (reply->old_ia != NULL)
ia_na_dereference(&reply->old_ia, MDL);
- if (reply->lease != NULL)
+ if (reply->lease != NULL) {
+ if (!lease_in_database) {
+ release_lease6(reply->lease->ipv6_pool, reply->lease);
+ }
iaaddr_dereference(&reply->lease, MDL);
+ }
if (reply->fixed.data != NULL)
data_string_forget(&reply->fixed, MDL);
ia_na->num_iaaddr = 0;
}
+/*
+ * Compare two IA_NA.
+ */
+isc_boolean_t
+ia_na_equal(const struct ia_na *a, const struct ia_na *b)
+{
+ isc_boolean_t found;
+ int i, j;
+
+ /*
+ * Handle cases where one or both of the inputs is NULL.
+ */
+ if (a == NULL) {
+ if (b == NULL) {
+ return ISC_TRUE;
+ } else {
+ return ISC_FALSE;
+ }
+ }
+
+ /*
+ * Check the DUID is the same.
+ */
+ if (a->iaid_duid.len != b->iaid_duid.len) {
+ return ISC_FALSE;
+ }
+ if (memcmp(a->iaid_duid.data,
+ b->iaid_duid.data, a->iaid_duid.len) != 0) {
+ return ISC_FALSE;
+ }
+
+ /*
+ * Make sure we have the same number of addresses in each.
+ */
+ if (a->num_iaaddr != b->num_iaaddr) {
+ return ISC_FALSE;
+ }
+
+ /*
+ * Check that each address is present in both.
+ */
+ for (i=0; i<a->num_iaaddr; i++) {
+ found = ISC_FALSE;
+ for (j=0; j<a->num_iaaddr; j++) {
+ if (memcmp(&(a->iaaddr[i]->addr),
+ &(b->iaaddr[j]->addr),
+ sizeof(struct in6_addr) == 0)) {
+ found = ISC_TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ return ISC_FALSE;
+ }
+ }
+
+ /*
+ * These are the same in every way we care about.
+ */
+ return ISC_TRUE;
+}
+
/*
* Helper function for lease heaps.
* Makes the top of the heap the oldest lease.