65f1ef1
diff -up dhcp-4.1.1/client/dhc6.c.sendDecline dhcp-4.1.1/client/dhc6.c
65f1ef1
--- dhcp-4.1.1/client/dhc6.c.sendDecline	2009-07-25 00:04:51.000000000 +0200
4bd0e9c
+++ dhcp-4.1.1/client/dhc6.c	2010-04-19 11:42:42.000000000 +0200
65f1ef1
@@ -95,6 +95,8 @@ void do_select6(void *input);
65f1ef1
 void do_refresh6(void *input);
65f1ef1
 static void do_release6(void *input);
65f1ef1
 static void start_bound(struct client_state *client);
65f1ef1
+static void start_decline6(struct client_state *client);
65f1ef1
+static void do_decline6(void *input);
65f1ef1
 static void start_informed(struct client_state *client);
65f1ef1
 void informed_handler(struct packet *packet, struct client_state *client);
65f1ef1
 void bound_handler(struct packet *packet, struct client_state *client);
65f1ef1
@@ -2137,6 +2139,7 @@ start_release6(struct client_state *clie
65f1ef1
 	cancel_timeout(do_select6, client);
65f1ef1
 	cancel_timeout(do_refresh6, client);
65f1ef1
 	cancel_timeout(do_release6, client);
65f1ef1
+	cancel_timeout(do_decline6, client);
65f1ef1
 	client->state = S_STOPPED;
65f1ef1
 
65f1ef1
 	/*
65f1ef1
@@ -2787,6 +2790,7 @@ dhc6_check_reply(struct client_state *cl
65f1ef1
 		break;
65f1ef1
 
65f1ef1
 	      case S_STOPPED:
65f1ef1
+	      case S_DECLINED:
65f1ef1
 		action = dhc6_stop_action;
65f1ef1
 		break;
65f1ef1
 
65f1ef1
@@ -2888,6 +2892,7 @@ dhc6_check_reply(struct client_state *cl
65f1ef1
 		break;
65f1ef1
 
65f1ef1
 	      case S_STOPPED:
65f1ef1
+	      case S_DECLINED:
65f1ef1
 		/* Nothing critical to do at this stage. */
65f1ef1
 		break;
65f1ef1
 
65f1ef1
@@ -3930,17 +3935,23 @@ reply_handler(struct packet *packet, str
65f1ef1
 	cancel_timeout(do_select6, client);
65f1ef1
 	cancel_timeout(do_refresh6, client);
65f1ef1
 	cancel_timeout(do_release6, client);
65f1ef1
+	cancel_timeout(do_decline6, client);
65f1ef1
 
65f1ef1
 	/* If this is in response to a Release/Decline, clean up and return. */
65f1ef1
-	if (client->state == S_STOPPED) {
65f1ef1
-		if (client->active_lease == NULL)
65f1ef1
-			return;
65f1ef1
+	if ((client->state == S_STOPPED) ||
4bd0e9c
+	    (client->state == S_DECLINED)) {
65f1ef1
+
65f1ef1
+		if (client->active_lease != NULL) {
65f1ef1
+			dhc6_lease_destroy(&client->active_lease, MDL);
65f1ef1
+			client->active_lease = NULL;
65f1ef1
+			/* We should never wait for nothing!? */
65f1ef1
+			if (stopping_finished())
65f1ef1
+				exit(0);
65f1ef1
+		}
65f1ef1
+
65f1ef1
+		if (client->state == S_DECLINED)
65f1ef1
+			start_init6(client);
65f1ef1
 
65f1ef1
-		dhc6_lease_destroy(&client->active_lease, MDL);
65f1ef1
-		client->active_lease = NULL;
65f1ef1
-		/* We should never wait for nothing!? */
65f1ef1
-		if (stopping_finished())
65f1ef1
-			exit(0);
65f1ef1
 		return;
65f1ef1
 	}
65f1ef1
 
65f1ef1
@@ -4463,7 +4474,11 @@ start_bound(struct client_state *client)
65f1ef1
 						     oldia, oldaddr);
65f1ef1
 			dhc6_marshall_values("new_", client, lease, ia, addr);
65f1ef1
 
65f1ef1
-			script_go(client);
65f1ef1
+			// when script returns 3, DAD failed
65f1ef1
+			if (script_go(client) == 3) {
65f1ef1
+				start_decline6(client);
65f1ef1
+				return;
65f1ef1
+			}
65f1ef1
 		}
65f1ef1
 
65f1ef1
 		/* XXX: maybe we should loop on the old values instead? */
4bd0e9c
@@ -4509,6 +4524,151 @@ start_bound(struct client_state *client)
65f1ef1
 	dhc6_check_times(client);
65f1ef1
 }
65f1ef1
 
65f1ef1
+/*
65f1ef1
+ * Decline addresses.
65f1ef1
+ */
65f1ef1
+void
65f1ef1
+start_decline6(struct client_state *client)
65f1ef1
+{
65f1ef1
+	/* Cancel any pending transmissions */
65f1ef1
+	cancel_timeout(do_confirm6, client);
65f1ef1
+	cancel_timeout(do_select6, client);
65f1ef1
+	cancel_timeout(do_refresh6, client);
65f1ef1
+	cancel_timeout(do_release6, client);
65f1ef1
+	cancel_timeout(do_decline6, client);
65f1ef1
+	client->state = S_DECLINED;
65f1ef1
+
65f1ef1
+	if (client->active_lease == NULL)
65f1ef1
+		return;
65f1ef1
+
65f1ef1
+	/* Set timers per RFC3315 section 18.1.7. */
65f1ef1
+	client->IRT = DEC_TIMEOUT * 100;
65f1ef1
+	client->MRT = 0;
65f1ef1
+	client->MRC = DEC_MAX_RC;
65f1ef1
+	client->MRD = 0;
65f1ef1
+
65f1ef1
+	dhc6_retrans_init(client);
65f1ef1
+	client->v6_handler = reply_handler;
65f1ef1
+
65f1ef1
+	client->refresh_type = DHCPV6_DECLINE;
65f1ef1
+	do_decline6(client);
65f1ef1
+}
65f1ef1
+
65f1ef1
+/*
65f1ef1
+ * do_decline6() creates a Decline packet and transmits it.
65f1ef1
+ */
65f1ef1
+static void
65f1ef1
+do_decline6(void *input)
65f1ef1
+{
65f1ef1
+	struct client_state *client;
65f1ef1
+	struct data_string ds;
65f1ef1
+	int send_ret;
4bd0e9c
+	struct timeval elapsed, tv;
65f1ef1
+
65f1ef1
+	client = input;
65f1ef1
+
65f1ef1
+	if ((client->active_lease == NULL) || !active_prefix(client))
65f1ef1
+		return;
65f1ef1
+
65f1ef1
+	if ((client->MRC != 0) && (client->txcount > client->MRC))  {
65f1ef1
+		log_info("Max retransmission count exceeded.");
65f1ef1
+		goto decline_done;
65f1ef1
+	}
65f1ef1
+
65f1ef1
+	/*
65f1ef1
+	 * Start_time starts at the first transmission.
65f1ef1
+	 */
65f1ef1
+	if (client->txcount == 0) {
65f1ef1
+		client->start_time.tv_sec = cur_tv.tv_sec;
65f1ef1
+		client->start_time.tv_usec = cur_tv.tv_usec;
65f1ef1
+	}
65f1ef1
+
4bd0e9c
+	/* elapsed = cur - start */
4bd0e9c
+	elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
4bd0e9c
+	elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
4bd0e9c
+	if (elapsed.tv_usec < 0) {
4bd0e9c
+		elapsed.tv_sec -= 1;
4bd0e9c
+		elapsed.tv_usec += 1000000;
4bd0e9c
+	}
4bd0e9c
+
65f1ef1
+	memset(&ds, 0, sizeof(ds));
65f1ef1
+	if (!buffer_allocate(&ds.buffer, 4, MDL)) {
65f1ef1
+		log_error("Unable to allocate memory for Decline.");
65f1ef1
+		goto decline_done;
65f1ef1
+	}
65f1ef1
+
65f1ef1
+	ds.data = ds.buffer->data;
65f1ef1
+	ds.len = 4;
65f1ef1
+	ds.buffer->data[0] = DHCPV6_DECLINE;
65f1ef1
+	memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
65f1ef1
+
4bd0e9c
+	/* Form an elapsed option. */
4bd0e9c
+	/* Maximum value is 65535 1/100s coded as 0xffff. */
4bd0e9c
+	if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
4bd0e9c
+	    ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
4bd0e9c
+		client->elapsed = 0xffff;
4bd0e9c
+	} else {
4bd0e9c
+		client->elapsed = elapsed.tv_sec * 100;
4bd0e9c
+		client->elapsed += elapsed.tv_usec / 10000;
4bd0e9c
+	}
4bd0e9c
+
4bd0e9c
+	client->elapsed = htons(client->elapsed);
4bd0e9c
+
65f1ef1
+	log_debug("XMT: Forming Decline.");
65f1ef1
+	make_client6_options(client, &client->sent_options,
65f1ef1
+			     client->active_lease, DHCPV6_DECLINE);
65f1ef1
+	dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
65f1ef1
+				    client->sent_options, &global_scope,
65f1ef1
+				    &dhcpv6_universe);
65f1ef1
+
65f1ef1
+	/* Append IA's (but don't release temporary addresses). */
65f1ef1
+	if (wanted_ia_na &&
65f1ef1
+	    dhc6_add_ia_na(client, &ds, client->active_lease,
65f1ef1
+			   DHCPV6_DECLINE) != ISC_R_SUCCESS) {
65f1ef1
+		data_string_forget(&ds, MDL);
65f1ef1
+		goto decline_done;
65f1ef1
+	}
65f1ef1
+	if (wanted_ia_pd &&
65f1ef1
+	    dhc6_add_ia_pd(client, &ds, client->active_lease,
65f1ef1
+			   DHCPV6_DECLINE) != ISC_R_SUCCESS) {
65f1ef1
+		data_string_forget(&ds, MDL);
65f1ef1
+		goto decline_done;
65f1ef1
+	}
65f1ef1
+
65f1ef1
+	/* Transmit and wait. */
65f1ef1
+	log_info("XMT: Decline on %s, interval %ld0ms.",
65f1ef1
+		 client->name ? client->name : client->interface->name,
65f1ef1
+		 (long int)client->RT);
65f1ef1
+
65f1ef1
+	send_ret = send_packet6(client->interface, ds.data, ds.len,
65f1ef1
+				&DHCPv6DestAddr);
65f1ef1
+	if (send_ret != ds.len) {
65f1ef1
+		log_error("dhc6: sendpacket6() sent %d of %d bytes",
65f1ef1
+			  send_ret, ds.len);
65f1ef1
+	}
65f1ef1
+
65f1ef1
+	data_string_forget(&ds, MDL);
65f1ef1
+
65f1ef1
+	/* Wait RT */
65f1ef1
+	tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
65f1ef1
+	tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
65f1ef1
+	if (tv.tv_usec >= 1000000) {
65f1ef1
+		tv.tv_sec += 1;
65f1ef1
+		tv.tv_usec -= 1000000;
65f1ef1
+	}
65f1ef1
+	add_timeout(&tv, do_decline6, client, NULL, NULL);
65f1ef1
+	dhc6_retrans_advance(client);
65f1ef1
+	return;
65f1ef1
+
65f1ef1
+decline_done:
65f1ef1
+	if (client->active_lease != NULL) {
65f1ef1
+		dhc6_lease_destroy(&client->active_lease, MDL);
65f1ef1
+		client->active_lease = NULL;
65f1ef1
+	}
65f1ef1
+	start_init6(client);
65f1ef1
+	return;
65f1ef1
+}
65f1ef1
+
65f1ef1
 /* While bound, ignore packets.  In the future we'll want to answer
65f1ef1
  * Reconfigure-Request messages and the like.
65f1ef1
  */