* An interface can now also be configured to be "auto config" (which means DHCP for now).

* Some minor cleanup in the DHCP client.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19465 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-12-12 01:16:28 +00:00
parent fb2b8194c2
commit 0ce7725e1c
3 changed files with 150 additions and 130 deletions

View File

@ -296,16 +296,13 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
{
fTransactionID = system_time();
dhcp_message discover(DHCP_DISCOVER);
discover.opcode = BOOT_REQUEST;
discover.hardware_type = ARP_HARDWARE_TYPE_ETHER;
discover.hardware_address_length = 6;
discover.transaction_id = htonl(fTransactionID);
discover.seconds_since_boot = htons(max_c(system_time() / 1000000LL, 65535));
fStatus = get_mac_address(device, discover.mac_address);
fStatus = get_mac_address(device, fMAC);
if (fStatus < B_OK)
return;
dhcp_message discover(DHCP_DISCOVER);
_PrepareMessage(discover);
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0) {
fStatus = errno;
@ -418,48 +415,7 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
BMessage address;
address.AddString("family", "inet");
address.AddString("address", _ToString(fAssignedAddress));
dhcp_option_cookie cookie;
message_option option;
const uint8 *data;
size_t size;
while (message->NextOption(cookie, option, data, size)) {
// iterate through all options
switch (option) {
case OPTION_ROUTER_ADDRESS:
address.AddString("gateway", _ToString(data));
break;
case OPTION_SUBNET_MASK:
address.AddString("mask", _ToString(data));
break;
case OPTION_DOMAIN_NAME_SERVER:
// TODO: for now, write it out to /etc/resolv.conf
for (uint32 i = 0; i < size / 4; i++) {
printf("DNS: %s\n", _ToString(&data[i*4]).String());
}
break;
case OPTION_SERVER_ADDRESS:
fServer.sin_addr.s_addr = *(in_addr_t*)data;
break;
case OPTION_ADDRESS_LEASE_TIME:
printf("lease time of %lu seconds\n", htonl(*(uint32*)data));
break;
case OPTION_HOST_NAME:
char name[256];
memcpy(name, data, size);
name[size] = '\0';
printf("DHCP host name: \"%s\"\n", name);
break;
case OPTION_MESSAGE_TYPE:
break;
default:
printf("unknown option %lu\n", (uint32)option);
break;
}
}
_ParseOptions(*message, address);
configure.AddMessage("address", &address);
@ -472,24 +428,9 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
&& status == B_OK) {
// configuration succeeded, request it from the server
_ResetTimeout(socket);
state = REQUESTING;
request.opcode = BOOT_REQUEST;
request.hardware_type = ARP_HARDWARE_TYPE_ETHER;
request.hardware_address_length = 6;
request.transaction_id = htonl(fTransactionID);
request.seconds_since_boot = htons(max_c(system_time() / 1000000LL, 65535));
memcpy(request.mac_address, discover.mac_address, 6);
// add server identifier option
uint8* next = request.options;
next = request.PutOption(next, OPTION_MESSAGE_TYPE, (uint8)DHCP_REQUEST);
next = request.PutOption(next, OPTION_MESSAGE_SIZE,
(uint16)sizeof(dhcp_message));
next = request.PutOption(next, OPTION_SERVER_ADDRESS,
(uint32)fServer.sin_addr.s_addr);
next = request.PutOption(next, OPTION_REQUEST_IP_ADDRESS, fAssignedAddress);
next = request.PutOption(next, OPTION_END);
_PrepareMessage(request);
fStatus = _SendMessage(socket, request, broadcast);
// we're sending a broadcast so that all offers get an answer
@ -533,24 +474,93 @@ DHCPClient::~DHCPClient()
// release lease
dhcp_message release(DHCP_RELEASE);
release.opcode = BOOT_REQUEST;
release.hardware_type = ARP_HARDWARE_TYPE_ETHER;
release.hardware_address_length = 6;
release.transaction_id = htonl(fTransactionID);
release.seconds_since_boot = htons(max_c(system_time() / 1000000LL, 65535));
get_mac_address(fDevice.String(), release.mac_address);
// add server identifier option
uint8* next = const_cast<uint8*>(release.LastOption());
next = release.PutOption(next, OPTION_SERVER_ADDRESS, (uint32)fServer.sin_addr.s_addr);
next = release.PutOption(next, OPTION_REQUEST_IP_ADDRESS, fAssignedAddress);
next = release.PutOption(next, OPTION_END);
_PrepareMessage(release);
_SendMessage(socket, release, fServer);
close(socket);
}
void
DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address)
{
dhcp_option_cookie cookie;
message_option option;
const uint8 *data;
size_t size;
while (message.NextOption(cookie, option, data, size)) {
// iterate through all options
switch (option) {
case OPTION_ROUTER_ADDRESS:
address.AddString("gateway", _ToString(data));
break;
case OPTION_SUBNET_MASK:
address.AddString("mask", _ToString(data));
break;
case OPTION_DOMAIN_NAME_SERVER:
// TODO: for now, write it out to /etc/resolv.conf
for (uint32 i = 0; i < size / 4; i++) {
printf("DNS: %s\n", _ToString(&data[i*4]).String());
}
break;
case OPTION_SERVER_ADDRESS:
fServer.sin_addr.s_addr = *(in_addr_t*)data;
break;
case OPTION_ADDRESS_LEASE_TIME:
printf("lease time of %lu seconds\n", htonl(*(uint32*)data));
break;
case OPTION_HOST_NAME:
char name[256];
memcpy(name, data, size);
name[size] = '\0';
printf("DHCP host name: \"%s\"\n", name);
break;
case OPTION_MESSAGE_TYPE:
break;
default:
printf("unknown option %lu\n", (uint32)option);
break;
}
}
}
void
DHCPClient::_PrepareMessage(dhcp_message& message)
{
message.opcode = BOOT_REQUEST;
message.hardware_type = ARP_HARDWARE_TYPE_ETHER;
message.hardware_address_length = 6;
message.transaction_id = htonl(fTransactionID);
message.seconds_since_boot = htons(max_c(system_time() / 1000000LL, 65535));
memcpy(message.mac_address, fMAC, 6);
switch (message.Type()) {
case DHCP_REQUEST:
case DHCP_RELEASE:
{
// add server identifier option
uint8* next = message.options;
next = message.PutOption(next, OPTION_MESSAGE_TYPE, (uint8)DHCP_REQUEST);
next = message.PutOption(next, OPTION_MESSAGE_SIZE,
(uint16)sizeof(dhcp_message));
next = message.PutOption(next, OPTION_SERVER_ADDRESS,
(uint32)fServer.sin_addr.s_addr);
next = message.PutOption(next, OPTION_REQUEST_IP_ADDRESS, fAssignedAddress);
next = message.PutOption(next, OPTION_END);
break;
}
default:
// the default options are fine
break;
}
}
void
DHCPClient::_ResetTimeout(int socket)
{

View File

@ -29,6 +29,8 @@ class DHCPClient : public BHandler {
virtual void MessageReceived(BMessage* message);
private:
void _ParseOptions(dhcp_message& message, BMessage& address);
void _PrepareMessage(dhcp_message& message);
status_t _SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const;
void _ResetTimeout(int socket);
bool _TimeoutShift(int socket);
@ -37,6 +39,7 @@ class DHCPClient : public BHandler {
BString fDevice;
BMessageRunner* fRunner;
uint8 fMAC[6];
uint32 fTransactionID;
in_addr_t fAssignedAddress;
sockaddr_in fServer;

View File

@ -48,7 +48,8 @@ class NetServer : public BApplication {
private:
bool _TestForInterface(int socket, const char* name);
status_t _ConfigureInterface(int socket, BMessage& interface);
status_t _ConfigureInterface(int socket, BMessage& interface,
bool fromMessage = false);
bool _QuitLooperForDevice(const char* device);
BLooper* _LooperForDevice(const char* device);
status_t _ConfigureDevice(int socket, const char* path);
@ -246,8 +247,8 @@ NetServer::MessageReceived(BMessage* message)
if (socket < 0)
break;
status_t status = _ConfigureInterface(socket, *message);
status_t status = _ConfigureInterface(socket, *message, true);
BMessage reply(B_REPLY);
reply.AddInt32("status", status);
message->SendReply(&reply);
@ -309,7 +310,7 @@ NetServer::_TestForInterface(int socket, const char* name)
status_t
NetServer::_ConfigureInterface(int socket, BMessage& interface)
NetServer::_ConfigureInterface(int socket, BMessage& interface, bool fromMessage)
{
const char *device;
if (interface.FindString("device", &device) != B_OK)
@ -319,6 +320,8 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface)
if (!prepare_request(request, device))
return B_ERROR;
bool startAutoConfig = false;
int32 flags;
if (interface.FindInt32("flags", &flags) < B_OK)
flags = IFF_UP;
@ -372,39 +375,59 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface)
// retrieve addresses
bool autoConfig;
if (addressMessage.FindBool("auto config", &autoConfig) != B_OK)
autoConfig = false;
if (autoConfig && fromMessage) {
// we don't accept auto-config messages this way
continue;
}
bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false;
struct sockaddr address, mask, peer, broadcast, gateway;
const char* string;
if (addressMessage.FindString("address", &string) == B_OK
&& parse_address(familyIndex, string, address)) {
hasAddress = true;
if (addressMessage.FindString("mask", &string) == B_OK
&& parse_address(familyIndex, string, mask))
hasMask = true;
if (!autoConfig) {
if (addressMessage.FindString("address", &string) == B_OK
&& parse_address(familyIndex, string, address)) {
hasAddress = true;
if (addressMessage.FindString("mask", &string) == B_OK
&& parse_address(familyIndex, string, mask))
hasMask = true;
}
if (addressMessage.FindString("peer", &string) == B_OK
&& parse_address(familyIndex, string, peer))
hasPeer = true;
if (addressMessage.FindString("broadcast", &string) == B_OK
&& parse_address(familyIndex, string, broadcast))
hasBroadcast = true;
}
if (addressMessage.FindString("peer", &string) == B_OK
&& parse_address(familyIndex, string, peer))
hasPeer = true;
if (addressMessage.FindString("broadcast", &string) == B_OK
&& parse_address(familyIndex, string, broadcast))
hasBroadcast = true;
// add gateway route, if we're asked for it
route_entry route;
memset(&route, 0, sizeof(route_entry));
route.flags = RTF_STATIC | RTF_DEFAULT;
if (addressMessage.FindString("gateway", &string) == B_OK
request.ifr_route = route;
ioctl(socket, SIOCDELRT, &request, sizeof(request));
// Try to remove a previous default route, doesn't matter
// if it fails.
if (autoConfig) {
// add a default route to make the interface accessible, even without an address
if (ioctl(socket, SIOCADDRT, &request, sizeof(request)) < 0) {
fprintf(stderr, "%s: Could not add route for %s: %s\n",
Name(), device, strerror(errno));
} else {
_QuitLooperForDevice(device);
startAutoConfig = true;
}
} else if (addressMessage.FindString("gateway", &string) == B_OK
&& parse_address(familyIndex, string, gateway)) {
route_entry route;
memset(&route, 0, sizeof(route_entry));
// add gateway route, if we're asked for it
route.flags = RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY;
route.gateway = &gateway;
request.ifr_route = route;
ioctl(socket, SIOCDELRT, &request, sizeof(request));
// Try to remove a previous default route, doesn't matter
// if it fails.
if (ioctl(socket, SIOCADDRT, &request, sizeof(request)) < 0) {
fprintf(stderr, "%s: Could not add route for %s: %s\n",
Name(), device, strerror(errno));
@ -516,6 +539,14 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface)
}
}
if (startAutoConfig) {
// start auto configuration
AutoconfigLooper* looper = new AutoconfigLooper(this, device);
looper->Run();
fDeviceMap[device] = looper;
}
return B_OK;
}
@ -550,40 +581,16 @@ NetServer::_LooperForDevice(const char* device)
status_t
NetServer::_ConfigureDevice(int socket, const char* path)
{
_QuitLooperForDevice(path);
// bring interface up, but don't configure it just yet
BMessage interface;
interface.AddString("device", path);
BMessage address;
address.AddString("family", "inet");
address.AddBool("auto config", true);
interface.AddMessage("address", &address);
status_t status = _ConfigureInterface(socket, interface);
if (status < B_OK)
return status;
// add a default route to make the interface accessible, even without an address
route_entry route;
memset(&route, 0, sizeof(route_entry));
route.flags = RTF_STATIC | RTF_DEFAULT;
ifreq request;
if (!prepare_request(request, path))
return B_ERROR;
request.ifr_route = route;
if (ioctl(socket, SIOCADDRT, &request, sizeof(request)) < 0) {
fprintf(stderr, "%s: Could not add route for %s: %s\n",
Name(), path, strerror(errno));
}
AutoconfigLooper* looper = new AutoconfigLooper(this, path);
looper->Run();
fDeviceMap[path] = looper;
return B_OK;
return _ConfigureInterface(socket, interface);
}