Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
dhcp.4389
0013-dhcp-4.2.x-dhcpv6-decline-on-DAD-failure.8...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0013-dhcp-4.2.x-dhcpv6-decline-on-DAD-failure.872609.patch of Package dhcp.4389
Author: Jiri Popelka <jpopelka@redhat.com> References: bsc#872609, ISC-Bugs#21237 Upstream: yes If the bound address failed DAD (is found to be in use on the link), the dhcpv6 client sends a Decline message to the server as described in section 18.1.7 of RFC-3315 (#559147) (Submitted to dhcp-bugs@isc.org - [ISC-Bugs #26735]) diff --git a/client/dhc6.c b/client/dhc6.c index 8974e7a..f8ad25d 100644 --- a/client/dhc6.c +++ b/client/dhc6.c @@ -96,6 +96,8 @@ void do_select6(void *input); void do_refresh6(void *input); static void do_release6(void *input); static void start_bound(struct client_state *client); +static void start_decline6(struct client_state *client); +static void do_decline6(void *input); static void start_informed(struct client_state *client); void informed_handler(struct packet *packet, struct client_state *client); void bound_handler(struct packet *packet, struct client_state *client); @@ -2080,6 +2082,7 @@ start_release6(struct client_state *client) cancel_timeout(do_select6, client); cancel_timeout(do_refresh6, client); cancel_timeout(do_release6, client); + cancel_timeout(do_decline6, client); client->state = S_STOPPED; /* @@ -2713,6 +2716,7 @@ dhc6_check_reply(struct client_state *client, struct dhc6_lease *new) break; case S_STOPPED: + case S_DECLINED: action = dhc6_stop_action; break; @@ -2814,6 +2818,7 @@ dhc6_check_reply(struct client_state *client, struct dhc6_lease *new) break; case S_STOPPED: + case S_DECLINED: /* Nothing critical to do at this stage. */ break; @@ -3804,17 +3809,23 @@ reply_handler(struct packet *packet, struct client_state *client) cancel_timeout(do_select6, client); cancel_timeout(do_refresh6, client); cancel_timeout(do_release6, client); + cancel_timeout(do_decline6, client); /* If this is in response to a Release/Decline, clean up and return. */ - if (client->state == S_STOPPED) { - if (client->active_lease == NULL) - return; + if ((client->state == S_STOPPED) || + (client->state == S_DECLINED)) { + + if (client->active_lease != NULL) { + dhc6_lease_destroy(&client->active_lease, MDL); + client->active_lease = NULL; + /* We should never wait for nothing!? */ + if (stopping_finished()) + exit(0); + } + + if (client->state == S_DECLINED) + start_init6(client); - dhc6_lease_destroy(&client->active_lease, MDL); - client->active_lease = NULL; - /* We should never wait for nothing!? */ - if (stopping_finished()) - exit(0); return; } @@ -4342,7 +4353,11 @@ start_bound(struct client_state *client) dhc6_marshall_values("new_", client, lease, ia, addr); script_write_requested6(client); - script_go(client); + // when script returns 3, DAD failed + if (script_go(client) == 3) { + start_decline6(client); + return; + } } /* XXX: maybe we should loop on the old values instead? */ @@ -4390,6 +4405,149 @@ start_bound(struct client_state *client) dhc6_check_times(client); } +/* + * Decline addresses. + */ +void +start_decline6(struct client_state *client) +{ + /* Cancel any pending transmissions */ + cancel_timeout(do_confirm6, client); + cancel_timeout(do_select6, client); + cancel_timeout(do_refresh6, client); + cancel_timeout(do_release6, client); + cancel_timeout(do_decline6, client); + client->state = S_DECLINED; + + if (client->active_lease == NULL) + return; + + /* Set timers per RFC3315 section 18.1.7. */ + client->IRT = DEC_TIMEOUT * 100; + client->MRT = 0; + client->MRC = DEC_MAX_RC; + client->MRD = 0; + + dhc6_retrans_init(client); + client->v6_handler = reply_handler; + + client->refresh_type = DHCPV6_DECLINE; + do_decline6(client); +} + +/* + * do_decline6() creates a Decline packet and transmits it. + */ +static void +do_decline6(void *input) +{ + struct client_state *client; + struct data_string ds; + int send_ret; + struct timeval elapsed, tv; + + client = input; + + if ((client->active_lease == NULL) || !active_prefix(client)) + return; + + if ((client->MRC != 0) && (client->txcount > client->MRC)) { + log_info("Max retransmission count exceeded."); + goto decline_done; + } + + /* + * Start_time starts at the first transmission. + */ + if (client->txcount == 0) { + client->start_time.tv_sec = cur_tv.tv_sec; + client->start_time.tv_usec = cur_tv.tv_usec; + } + + /* elapsed = cur - start */ + elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec; + elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec; + if (elapsed.tv_usec < 0) { + elapsed.tv_sec -= 1; + elapsed.tv_usec += 1000000; + } + + memset(&ds, 0, sizeof(ds)); + if (!buffer_allocate(&ds.buffer, 4, MDL)) { + log_error("Unable to allocate memory for Decline."); + goto decline_done; + } + + ds.data = ds.buffer->data; + ds.len = 4; + ds.buffer->data[0] = DHCPV6_DECLINE; + memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3); + + /* Form an elapsed option. */ + /* Maximum value is 65535 1/100s coded as 0xffff. */ + if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) || + ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) { + client->elapsed = 0xffff; + } else { + client->elapsed = elapsed.tv_sec * 100; + client->elapsed += elapsed.tv_usec / 10000; + } + + client->elapsed = htons(client->elapsed); + + log_debug("XMT: Forming Decline."); + make_client6_options(client, &client->sent_options, + client->active_lease, DHCPV6_DECLINE); + dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, + client->sent_options, &global_scope, + &dhcpv6_universe); + + /* Append IA's (but don't release temporary addresses). */ + if (wanted_ia_na && + dhc6_add_ia_na(client, &ds, client->active_lease, + DHCPV6_DECLINE) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + goto decline_done; + } + if (wanted_ia_pd && + dhc6_add_ia_pd(client, &ds, client->active_lease, + DHCPV6_DECLINE) != ISC_R_SUCCESS) { + data_string_forget(&ds, MDL); + goto decline_done; + } + + /* Transmit and wait. */ + log_info("XMT: Decline on %s, interval %ld0ms.", + client->name ? client->name : client->interface->name, + (long int)client->RT); + + send_ret = send_packet6(client->interface, ds.data, ds.len, + &DHCPv6DestAddr); + if (send_ret != ds.len) { + log_error("dhc6: sendpacket6() sent %d of %d bytes", + send_ret, ds.len); + } + + data_string_forget(&ds, MDL); + + /* Wait RT */ + tv.tv_sec = cur_tv.tv_sec + client->RT / 100; + tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; + if (tv.tv_usec >= 1000000) { + tv.tv_sec += 1; + tv.tv_usec -= 1000000; + } + add_timeout(&tv, do_decline6, client, NULL, NULL); + dhc6_retrans_advance(client); + return; + +decline_done: + dhc6_lease_destroy(&client->active_lease, MDL); + client->active_lease = NULL; + start_init6(client); + return; +} + /* While bound, ignore packets. In the future we'll want to answer * Reconfigure-Request messages and the like. */ diff --git a/includes/dhcpd.h b/includes/dhcpd.h index a52992b..0eda51d 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -1060,7 +1060,8 @@ enum dhcp_state { S_BOUND = 5, S_RENEWING = 6, S_REBINDING = 7, - S_STOPPED = 8 + S_STOPPED = 8, + S_DECLINED = 9 }; /* Authentication and BOOTP policy possibilities (not all values work
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor