diff --git a/base/services/dhcpcsvc/dhcp/api.c b/base/services/dhcpcsvc/dhcp/api.c index e294cb72798..ab85e5e58f8 100644 --- a/base/services/dhcpcsvc/dhcp/api.c +++ b/base/services/dhcpcsvc/dhcp/api.c @@ -144,24 +144,12 @@ Server_ReleaseParameters( DPRINT("Adapter: %p\n", Adapter); - if (Adapter->NteContext) - { - DeleteIPAddress(Adapter->NteContext); - Adapter->NteContext = 0; - } - if (Adapter->RouterMib.dwForwardNextHop) - { - DeleteIpForwardEntry(&Adapter->RouterMib); - Adapter->RouterMib.dwForwardNextHop = 0; - } + state_release(&Adapter->DhclientInfo); proto = find_protocol_by_adapter(&Adapter->DhclientInfo); if (proto) remove_protocol(proto); - Adapter->DhclientInfo.client->active = NULL; - Adapter->DhclientInfo.client->state = S_INIT; - if (hAdapterStateChangedEvent != NULL) SetEvent(hAdapterStateChangedEvent); diff --git a/base/services/dhcpcsvc/dhcp/dhclient.c b/base/services/dhcpcsvc/dhcp/dhclient.c index f25cae4a7ba..59a6eb9bcfc 100644 --- a/base/services/dhcpcsvc/dhcp/dhclient.c +++ b/base/services/dhcpcsvc/dhcp/dhclient.c @@ -227,6 +227,28 @@ state_init(void *ipp) send_discover(ip); } +void +state_release(void *ipp) +{ + struct interface_info *ip = ipp; + ULONG foo = (ULONG) GetTickCount(); + + ASSERT_STATE(state, S_BOUND); + + /* Make a DHCPRELEASE packet, and set appropriate per-interface + flags. */ + make_release(ip, ip->client->active); + + /* make_request doesn't initialize xid because it normally comes + from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, + so pick an xid now. */ + ip->client->xid = RtlRandom(&foo); + send_release(ip); + + ip->client->state = S_RELEASED; + unbind_lease(ip); +} + /* * state_selecting is called when one or more DHCPOFFER packets * have been received and a configurable period of time has passed. @@ -379,6 +401,7 @@ dhcpack(struct packet *packet) ip->client->new->renewal / 2 + ip->client->new->renewal / 4; #ifdef __REACTOS__ + ip->client->new->lease = ip->client->new->expiry; ip->client->new->obtained = cur_time; #endif ip->client->new->expiry += cur_time; @@ -439,6 +462,23 @@ void set_name_servers( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) { } +void +unset_name_servers( + PDHCP_ADAPTER Adapter) +{ + CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; + HKEY RegKey; + + strcat(Buffer, Adapter->DhclientInfo.name); + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &RegKey ) != ERROR_SUCCESS) + return; + + RegDeleteValueW( RegKey, L"DhcpNameServer" ); + + RegCloseKey( RegKey ); +} + + void set_domain(PDHCP_ADAPTER Adapter, struct client_lease *new_lease) @@ -489,12 +529,40 @@ set_domain(PDHCP_ADAPTER Adapter, } +void +unset_domain( + PDHCP_ADAPTER Adapter) +{ + CHAR Buffer1[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; + CHAR Buffer2[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; + HKEY RegKey1, RegKey2; + + strcat(Buffer1, Adapter->DhclientInfo.name); + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer1, 0, KEY_WRITE, &RegKey1 ) != ERROR_SUCCESS) + { + return; + } + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer2, 0, KEY_WRITE, &RegKey2 ) != ERROR_SUCCESS) + { + RegCloseKey(RegKey1); + return; + } + + RegDeleteValueW(RegKey1, L"DhcpDomain"); + RegDeleteValueW(RegKey2, L"DhcpDomain"); + + RegCloseKey(RegKey1); + RegCloseKey(RegKey2); +} + + void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) { CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; struct iaddr netmask; HKEY hkey; int i; - DWORD dwEnableDHCP; strcat(Buffer, Adapter->DhclientInfo.name); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS) @@ -530,12 +598,13 @@ void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) { strcat(Buffer, "."); } RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1); - dwEnableDHCP = 1; - RegSetValueExA(hkey, "EnableDHCP", 0, REG_DWORD, (LPBYTE)&dwEnableDHCP, sizeof(DWORD)); + RegSetValueExA(hkey, "DhcpServer", 0, REG_SZ, (LPBYTE)piaddr(new_lease->serveraddress), strlen(piaddr(new_lease->serveraddress))+1); + RegSetValueExA(hkey, "Lease", 0, REG_DWORD, (LPBYTE)&new_lease->lease, sizeof(DWORD)); RegSetValueExA(hkey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&new_lease->obtained, sizeof(DWORD)); RegSetValueExA(hkey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&new_lease->expiry, sizeof(DWORD)); - RegSetValueExA(hkey, "DhcpServer", 0, REG_SZ, (LPBYTE)piaddr(new_lease->serveraddress), strlen(piaddr(new_lease->serveraddress))+1); + RegSetValueExA(hkey, "T1", 0, REG_DWORD, (LPBYTE)&new_lease->renewal, sizeof(DWORD)); + RegSetValueExA(hkey, "T2", 0, REG_DWORD, (LPBYTE)&new_lease->rebind, sizeof(DWORD)); } if( !NT_SUCCESS(Status) ) @@ -579,6 +648,56 @@ void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) { RegCloseKey(hkey); } +void +reset_adapter( PDHCP_ADAPTER Adapter) { + CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; + CHAR IpAddress[] = "0.0.0.0"; + CHAR SubnetMask[] = "255.0.0.0"; + CHAR Server[] = "255.255.255.255"; + HKEY hkey; + DWORD lease; + time_t cur_time, new_time; + + time(&cur_time); + + strcat(Buffer, Adapter->DhclientInfo.name); + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS) + hkey = NULL; + + if( Adapter->NteContext ) + { + DeleteIPAddress( Adapter->NteContext ); + Adapter->NteContext = 0; + } + + if (hkey) { + RegSetValueExA(hkey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)IpAddress, strlen(IpAddress)+1); + RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)SubnetMask, strlen(SubnetMask)+1); + RegSetValueExA(hkey, "DhcpServer", 0, REG_SZ, (LPBYTE)Server, strlen(Server)+1); + + lease = 3600; + RegSetValueExA(hkey, "Lease", 0, REG_DWORD, (LPBYTE)&lease, sizeof(DWORD)); + RegSetValueExA(hkey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD)); + new_time = cur_time + lease; + RegSetValueExA(hkey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&new_time, sizeof(DWORD)); + new_time = cur_time + (lease / 2); + RegSetValueExA(hkey, "T1", 0, REG_DWORD, (LPBYTE)&new_time, sizeof(DWORD)); + new_time = cur_time + lease - (lease / 8); + RegSetValueExA(hkey, "T2", 0, REG_DWORD, (LPBYTE)&new_time, sizeof(DWORD)); + } + + if( Adapter->RouterMib.dwForwardNextHop ) { + DeleteIpForwardEntry( &Adapter->RouterMib ); + } + + if (hkey) { + RegDeleteValueA(hkey, "DhcpDefaultGateway"); + } + + if (hkey) + RegCloseKey(hkey); +} + void bind_lease(struct interface_info *ip) @@ -622,6 +741,28 @@ bind_lease(struct interface_info *ip) set_domain( Adapter, new_lease ); } +void +unbind_lease(struct interface_info *ip) +{ + PDHCP_ADAPTER Adapter; + + if (ip->client->active) { + free_client_lease(ip->client->active); + ip->client->active = NULL; + } + + Adapter = AdapterFindInfo( ip ); + if (Adapter) { + reset_adapter(Adapter); + unset_name_servers(Adapter); + unset_domain(Adapter); + } + else { + warning("Could not find adapter for info %p\n", ip); + return; + } +} + /* * state_bound is called when we've successfully bound to a particular * lease, but the renewal time on that lease has expired. We are @@ -874,8 +1015,16 @@ packet_to_lease(struct packet *packet) lease->address.len = sizeof(packet->raw->yiaddr); memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); #ifdef __REACTOS__ - lease->serveraddress.len = sizeof(packet->raw->siaddr); - memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len); + if (packet->raw->siaddr.S_un.S_addr == 0) + { + lease->serveraddress.len = packet->client_addr.len; + memcpy(lease->serveraddress.iabuf, &packet->client_addr.iabuf, packet->client_addr.len); + } + else + { + lease->serveraddress.len = sizeof(packet->raw->siaddr); + memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->serveraddress.len); + } #endif /* If the server name was filled out, copy it. */ @@ -1256,6 +1405,31 @@ send_decline(void *ipp) inaddr_any, &sockaddr_broadcast, NULL); } +void +send_release(void *ipp) +{ + struct interface_info *ip = ipp; + struct sockaddr_in destination; + struct in_addr from; + + memset(&destination, 0, sizeof(destination)); + memcpy(&destination.sin_addr.s_addr, + ip->client->destination.iabuf, + sizeof(destination.sin_addr.s_addr)); + destination.sin_port = htons(REMOTE_PORT); + destination.sin_family = AF_INET; + + memcpy(&from, ip->client->active->address.iabuf, + sizeof(from)); + + note("DHCPRELEASE on %s to %s port %d", ip->name, + inet_ntoa(destination.sin_addr), ntohs(destination.sin_port)); + + /* Send out a packet. */ + (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, + from, &destination, NULL); +} + void make_discover(struct interface_info *ip, struct client_lease *lease) { @@ -1515,6 +1689,70 @@ make_decline(struct interface_info *ip, struct client_lease *lease) ip->hw_address.haddr, ip->hw_address.hlen); } +void +make_release(struct interface_info *ip, struct client_lease *lease) +{ + struct tree_cache *options[256], message_type_tree; + struct tree_cache server_id_tree, client_id_tree; + unsigned char release = DHCPRELEASE; + int i; + + memset(options, 0, sizeof(options)); + memset(&ip->client->packet, 0, sizeof(ip->client->packet)); + + /* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */ + i = DHO_DHCP_MESSAGE_TYPE; + options[i] = &message_type_tree; + options[i]->value = &release; + options[i]->len = sizeof(release); + options[i]->buf_size = sizeof(release); + options[i]->timeout = 0xFFFFFFFF; + + /* Send back the server identifier... */ + i = DHO_DHCP_SERVER_IDENTIFIER; + options[i] = &server_id_tree; + options[i]->value = lease->options[i].data; + options[i]->len = lease->options[i].len; + options[i]->buf_size = lease->options[i].len; + options[i]->timeout = 0xFFFFFFFF; + + /* Send the uid if the user supplied one. */ + i = DHO_DHCP_CLIENT_IDENTIFIER; + if (ip->client->config->send_options[i].len) + { + options[i] = &client_id_tree; + options[i]->value = ip->client->config->send_options[i].data; + options[i]->len = ip->client->config->send_options[i].len; + options[i]->buf_size = ip->client->config->send_options[i].len; + options[i]->timeout = 0xFFFFFFFF; + } + + /* Set up the option buffer... */ + ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options); + if (ip->client->packet_length < BOOTP_MIN_LEN) + ip->client->packet_length = BOOTP_MIN_LEN; + + ip->client->packet.op = BOOTREQUEST; + ip->client->packet.htype = ip->hw_address.htype; + ip->client->packet.hlen = ip->hw_address.hlen; + ip->client->packet.hops = 0; + ip->client->packet.xid = 0; + ip->client->packet.secs = 0; + ip->client->packet.flags = 0; + + /* ciaddr is the address to be released */ + memcpy(&ip->client->packet.ciaddr, + lease->address.iabuf, lease->address.len); + memset(&ip->client->packet.yiaddr, 0, + sizeof(ip->client->packet.yiaddr)); + memset(&ip->client->packet.siaddr, 0, + sizeof(ip->client->packet.siaddr)); + memset(&ip->client->packet.giaddr, 0, + sizeof(ip->client->packet.giaddr)); + memcpy(ip->client->packet.chaddr, + ip->hw_address.haddr, ip->hw_address.hlen); +} + void free_client_lease(struct client_lease *lease) { diff --git a/base/services/dhcpcsvc/include/dhcpd.h b/base/services/dhcpcsvc/include/dhcpd.h index 4cf5b6e1607..4782ca88c10 100644 --- a/base/services/dhcpcsvc/include/dhcpd.h +++ b/base/services/dhcpcsvc/include/dhcpd.h @@ -156,6 +156,7 @@ struct client_lease { struct iaddr address; char *server_name; #ifdef __REACTOS__ + u_int32_t lease; time_t obtained; struct iaddr serveraddress; #endif @@ -175,7 +176,8 @@ enum dhcp_state { S_BOUND, S_RENEWING, S_REBINDING, - S_STATIC + S_STATIC, + S_RELEASED }; struct client_config { @@ -203,6 +205,7 @@ struct client_config { bootp_policy; struct string_list *medium; struct iaddrlist *reject_list; + char *user_class; }; struct client_state { @@ -405,19 +408,23 @@ void dhcpnak(struct packet *); void send_discover(void *); void send_request(void *); void send_decline(void *); +void send_release(void *); void state_reboot(void *); void state_init(void *); +void state_release(void *); void state_selecting(void *); void state_requesting(void *); void state_bound(void *); void state_panic(void *); void bind_lease(struct interface_info *); +void unbind_lease(struct interface_info *); void make_discover(struct interface_info *, struct client_lease *); void make_request(struct interface_info *, struct client_lease *); void make_decline(struct interface_info *, struct client_lease *); +void make_release(struct interface_info *, struct client_lease *); void free_client_lease(struct client_lease *); void rewrite_client_leases(struct interface_info *);