The beginnings of automatic configuration of network devices using DHCP; this is
currently only triggered when there is no configuration file - it can't be configured this way yet. All DHCP currently does is to send a UDP broadcast DHCP discover message. More to come. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19437 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "AutoconfigLooper.h"
|
||||||
|
#include "DHCPClient.h"
|
||||||
|
#include "NetServer.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <net/if_types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const uint32 kMsgReadyToRun = 'rdyr';
|
||||||
|
|
||||||
|
|
||||||
|
AutoconfigLooper::AutoconfigLooper(BMessenger target, const char* device)
|
||||||
|
: BLooper(device),
|
||||||
|
fTarget(target),
|
||||||
|
fDevice(device)
|
||||||
|
{
|
||||||
|
BMessage ready(kMsgReadyToRun);
|
||||||
|
PostMessage(&ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AutoconfigLooper::~AutoconfigLooper()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AutoconfigLooper::_ReadyToRun()
|
||||||
|
{
|
||||||
|
// start with DHCP
|
||||||
|
|
||||||
|
DHCPClient* client = new DHCPClient(fDevice.String());
|
||||||
|
if (client->InitCheck() == B_OK) {
|
||||||
|
AddHandler(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
puts("DHCP failed miserably!");
|
||||||
|
|
||||||
|
// DHCP obviously didn't work out, take some default values for now
|
||||||
|
// TODO: have a look at zeroconf
|
||||||
|
// TODO: this could also be done add-on based
|
||||||
|
|
||||||
|
BMessage interface;
|
||||||
|
interface.AddString("device", fDevice.String());
|
||||||
|
|
||||||
|
uint8 mac[6];
|
||||||
|
uint8 last = 56;
|
||||||
|
if (get_mac_address(fDevice.String(), mac) == B_OK) {
|
||||||
|
// choose IP address depending on the MAC address, if available
|
||||||
|
last = mac[0] ^ mac[1] ^ mac[2] ^ mac[3] ^ mac[4] ^ mac[5];
|
||||||
|
if (last > 253)
|
||||||
|
last = 253;
|
||||||
|
else if (last == 0)
|
||||||
|
last = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char string[64];
|
||||||
|
snprintf(string, sizeof(string), "192.168.0.%u", last);
|
||||||
|
|
||||||
|
BMessage address;
|
||||||
|
address.AddString("family", "inet");
|
||||||
|
address.AddString("address", string);
|
||||||
|
address.AddString("gateway", "192.168.0.254");
|
||||||
|
interface.AddMessage("address", &address);
|
||||||
|
|
||||||
|
fTarget.SendMessage(kMsgConfigureInterface, &interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AutoconfigLooper::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case kMsgReadyToRun:
|
||||||
|
_ReadyToRun();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BLooper::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef AUTOCONFIG_LOOPER_H
|
||||||
|
#define AUTOCONFIG_LOOPER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Looper.h>
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
class AutoconfigLooper : public BLooper {
|
||||||
|
public:
|
||||||
|
AutoconfigLooper(BMessenger target, const char* device);
|
||||||
|
virtual ~AutoconfigLooper();
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
BMessenger Target() const { return fTarget; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _ReadyToRun();
|
||||||
|
|
||||||
|
BMessenger fTarget;
|
||||||
|
BString fDevice;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AUTOCONFIG_LOOPER_H
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "DHCPClient.h"
|
||||||
|
#include "NetServer.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
// See RFC 2131 for DHCP, see RFC 1533 for BOOTP/DHCP options
|
||||||
|
|
||||||
|
#define DHCP_CLIENT_PORT 68
|
||||||
|
#define DHCP_SERVER_PORT 67
|
||||||
|
|
||||||
|
enum message_opcode {
|
||||||
|
BOOT_REQUEST = 1,
|
||||||
|
BOOT_REPLY
|
||||||
|
};
|
||||||
|
|
||||||
|
enum message_option {
|
||||||
|
OPTION_MAGIC = 0x63825363,
|
||||||
|
|
||||||
|
// generic options
|
||||||
|
OPTION_PAD = 0,
|
||||||
|
OPTION_END = 1,
|
||||||
|
OPTION_DATAGRAM_SIZE = 22,
|
||||||
|
OPTION_MTU = 26,
|
||||||
|
OPTION_BROADCAST_ADDRESS = 28,
|
||||||
|
OPTION_NETWORK_TIME_SERVERS = 42,
|
||||||
|
|
||||||
|
// DHCP specific options
|
||||||
|
OPTION_REQUEST_IP_ADDRESS = 50,
|
||||||
|
OPTION_ADDRESS_LEASE_TIME = 51,
|
||||||
|
OPTION_OVERLOAD = 52,
|
||||||
|
OPTION_MESSAGE_TYPE = 53,
|
||||||
|
OPTION_SERVER_ADDRESS = 54,
|
||||||
|
OPTION_REQUEST_PARAMETERS = 55,
|
||||||
|
OPTION_ERROR_MESSAGE = 56,
|
||||||
|
OPTION_MESSAGE_SIZE = 57,
|
||||||
|
OPTION_RENEWAL_TIME = 58,
|
||||||
|
OPTION_REBINDING_TIME = 59,
|
||||||
|
OPTION_CLASS_IDENTIFIER = 60,
|
||||||
|
OPTION_CLIENT_IDENTIFIER = 61,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum message_type {
|
||||||
|
DHCP_DISCOVER = 1,
|
||||||
|
DHCP_OFFER,
|
||||||
|
DHCP_REQUEST,
|
||||||
|
DHCP_DECLINE,
|
||||||
|
DHCP_ACK,
|
||||||
|
DHCP_NAK,
|
||||||
|
DHCP_RELEASE,
|
||||||
|
DHCP_INFORM
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dhcp_option_cookie {
|
||||||
|
dhcp_option_cookie() : state(0), file_has_options(false), server_name_has_options(false) {}
|
||||||
|
|
||||||
|
const uint8* next;
|
||||||
|
uint8 state;
|
||||||
|
bool file_has_options;
|
||||||
|
bool server_name_has_options;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dhcp_message {
|
||||||
|
dhcp_message(message_type type);
|
||||||
|
|
||||||
|
uint8 opcode;
|
||||||
|
uint8 hardware_type;
|
||||||
|
uint8 hardware_address_length;
|
||||||
|
uint8 hop_count;
|
||||||
|
uint32 transaction_id;
|
||||||
|
uint16 seconds_since_boot;
|
||||||
|
uint16 flags;
|
||||||
|
in_addr_t client_address;
|
||||||
|
in_addr_t your_address;
|
||||||
|
in_addr_t server_address;
|
||||||
|
in_addr_t gateway_address;
|
||||||
|
uint8 mac_address[16];
|
||||||
|
uint8 server_name[64];
|
||||||
|
uint8 file[128];
|
||||||
|
uint32 options_magic;
|
||||||
|
uint8 options[1260];
|
||||||
|
|
||||||
|
size_t MinSize() const { return 576; }
|
||||||
|
size_t Size() const;
|
||||||
|
|
||||||
|
bool HasOptions() const;
|
||||||
|
bool NextOption(dhcp_option_cookie& cookie, message_option& option,
|
||||||
|
const uint8*& data, size_t& size) const;
|
||||||
|
const uint8* LastOption() const;
|
||||||
|
|
||||||
|
uint8* PutOption(uint8* options, message_option option);
|
||||||
|
uint8* PutOption(uint8* options, message_option option, uint8 data);
|
||||||
|
uint8* PutOption(uint8* options, message_option option, uint16 data);
|
||||||
|
uint8* PutOption(uint8* options, message_option option, uint32 data);
|
||||||
|
uint8* PutOption(uint8* options, message_option option, uint8* data, uint32 size);
|
||||||
|
} _PACKED;
|
||||||
|
|
||||||
|
|
||||||
|
#define ARP_HARDWARE_TYPE_ETHER 1
|
||||||
|
|
||||||
|
|
||||||
|
dhcp_message::dhcp_message(message_type type)
|
||||||
|
{
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
options_magic = htonl(OPTION_MAGIC);
|
||||||
|
|
||||||
|
uint8* next = options;
|
||||||
|
next = PutOption(next, OPTION_MESSAGE_TYPE, (uint8)type);
|
||||||
|
next = PutOption(next, OPTION_MESSAGE_SIZE, (uint16)sizeof(dhcp_message));
|
||||||
|
next = PutOption(next, OPTION_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
dhcp_message::HasOptions() const
|
||||||
|
{
|
||||||
|
return options_magic == htonl(OPTION_MAGIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
dhcp_message::NextOption(dhcp_option_cookie& cookie,
|
||||||
|
message_option& option, const uint8*& data, size_t& size) const
|
||||||
|
{
|
||||||
|
if (cookie.state == 0) {
|
||||||
|
if (!HasOptions())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cookie.state++;
|
||||||
|
cookie.next = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 bytesLeft = 0;
|
||||||
|
|
||||||
|
switch (cookie.state) {
|
||||||
|
case 1:
|
||||||
|
// options from "options"
|
||||||
|
bytesLeft = sizeof(options) + cookie.next - options;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// options from "file"
|
||||||
|
bytesLeft = sizeof(options) + cookie.next - options;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// options from "server_name"
|
||||||
|
bytesLeft = sizeof(options) + cookie.next - options;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (bytesLeft == 0) {
|
||||||
|
// TODO: suppport OPTION_OVERLOAD!
|
||||||
|
cookie.state = 4;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
option = (message_option)cookie.next[0];
|
||||||
|
if (option == OPTION_END) {
|
||||||
|
cookie.state = 4;
|
||||||
|
return false;
|
||||||
|
} else if (option == OPTION_PAD) {
|
||||||
|
bytesLeft--;
|
||||||
|
cookie.next++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = cookie.next[1];
|
||||||
|
data = &cookie.next[2];
|
||||||
|
cookie.next += 2 + size;
|
||||||
|
|
||||||
|
if (option == OPTION_OVERLOAD) {
|
||||||
|
cookie.file_has_options = data[0] & 1;
|
||||||
|
cookie.server_name_has_options = data[0] & 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8*
|
||||||
|
dhcp_message::LastOption() const
|
||||||
|
{
|
||||||
|
dhcp_option_cookie cookie;
|
||||||
|
message_option option;
|
||||||
|
const uint8 *data;
|
||||||
|
size_t size;
|
||||||
|
while (NextOption(cookie, option, data, size)) {
|
||||||
|
// iterate through all options
|
||||||
|
}
|
||||||
|
|
||||||
|
return cookie.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
dhcp_message::Size() const
|
||||||
|
{
|
||||||
|
const uint8* last = LastOption();
|
||||||
|
return sizeof(dhcp_message) - sizeof(options) + last + 1 - options;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8*
|
||||||
|
dhcp_message::PutOption(uint8* options, message_option option)
|
||||||
|
{
|
||||||
|
options[0] = option;
|
||||||
|
return options + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8*
|
||||||
|
dhcp_message::PutOption(uint8* options, message_option option, uint8 data)
|
||||||
|
{
|
||||||
|
return PutOption(options, option, &data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8*
|
||||||
|
dhcp_message::PutOption(uint8* options, message_option option, uint16 data)
|
||||||
|
{
|
||||||
|
data = htons(data);
|
||||||
|
return PutOption(options, option, (uint8*)&data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8*
|
||||||
|
dhcp_message::PutOption(uint8* options, message_option option, uint32 data)
|
||||||
|
{
|
||||||
|
data = htonl(data);
|
||||||
|
return PutOption(options, option, (uint8*)&data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8*
|
||||||
|
dhcp_message::PutOption(uint8* options, message_option option, uint8* data, uint32 size)
|
||||||
|
{
|
||||||
|
options[0] = option;
|
||||||
|
options[1] = size;
|
||||||
|
memcpy(&options[2], data, size);
|
||||||
|
|
||||||
|
return options + 2 + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
DHCPClient::DHCPClient(const char* device)
|
||||||
|
: BHandler("dhcp"),
|
||||||
|
fDevice(device)
|
||||||
|
{
|
||||||
|
fTransactionID = system_time();
|
||||||
|
|
||||||
|
dhcp_message message(DHCP_DISCOVER);
|
||||||
|
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));
|
||||||
|
fStatus = get_mac_address(device, message.mac_address);
|
||||||
|
if (fStatus < B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (socket < 0) {
|
||||||
|
fStatus = errno;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in local;
|
||||||
|
memset(&local, 0, sizeof(struct sockaddr_in));
|
||||||
|
local.sin_family = AF_INET;
|
||||||
|
local.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
local.sin_port = htons(DHCP_CLIENT_PORT);
|
||||||
|
local.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
|
||||||
|
fStatus = errno;
|
||||||
|
close(socket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in broadcast;
|
||||||
|
memset(&broadcast, 0, sizeof(struct sockaddr_in));
|
||||||
|
broadcast.sin_family = AF_INET;
|
||||||
|
broadcast.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
broadcast.sin_port = htons(DHCP_SERVER_PORT);
|
||||||
|
broadcast.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
|
|
||||||
|
int option = 1;
|
||||||
|
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
|
||||||
|
|
||||||
|
printf("DHCP message size %lu\n", message.Size());
|
||||||
|
|
||||||
|
ssize_t bytesSent = sendto(socket, &message, message.MinSize(), 0,
|
||||||
|
(struct sockaddr*)&broadcast, sizeof(broadcast));
|
||||||
|
if (bytesSent < 0) {
|
||||||
|
fStatus = errno;
|
||||||
|
close(socket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(socket);
|
||||||
|
fStatus = B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DHCPClient::~DHCPClient()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DHCPClient::InitCheck()
|
||||||
|
{
|
||||||
|
printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus));
|
||||||
|
return fStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DHCPClient::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
BHandler::MessageReceived(message);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef DHCP_CLIENT_H
|
||||||
|
#define DHCP_CLIENT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Handler.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BMessageRunner;
|
||||||
|
|
||||||
|
class DHCPClient : public BHandler {
|
||||||
|
public:
|
||||||
|
DHCPClient(const char* device);
|
||||||
|
virtual ~DHCPClient();
|
||||||
|
|
||||||
|
status_t InitCheck();
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fDevice;
|
||||||
|
BMessageRunner* fRunner;
|
||||||
|
uint32 fTransactionID;
|
||||||
|
status_t fStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DHCP_CLIENT_H
|
||||||
@@ -11,11 +11,14 @@ AddResources net_server : net_server.rdef ;
|
|||||||
Server net_server :
|
Server net_server :
|
||||||
NetServer.cpp
|
NetServer.cpp
|
||||||
Settings.cpp
|
Settings.cpp
|
||||||
|
AutoconfigLooper.cpp
|
||||||
|
DHCPClient.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
LinkAgainst net_server :
|
LinkAgainst net_server :
|
||||||
be
|
be
|
||||||
libnetwork.so
|
libnetwork.so
|
||||||
|
$(TARGET_LIBSTDC++)
|
||||||
|
|
||||||
# for PPP
|
# for PPP
|
||||||
#libppp.a
|
#libppp.a
|
||||||
|
|||||||
+128
-21
@@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "AutoconfigLooper.h"
|
||||||
|
#include "NetServer.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
|
||||||
#include <Alert.h>
|
#include <Alert.h>
|
||||||
@@ -18,20 +20,24 @@
|
|||||||
#include <TextView.h>
|
#include <TextView.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <net/if.h>
|
|
||||||
#include <net/if_dl.h>
|
#include <net/if_dl.h>
|
||||||
#include <net/if_types.h>
|
#include <net/if_types.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::map<std::string, BLooper*> LooperMap;
|
||||||
|
|
||||||
|
|
||||||
class NetServer : public BApplication {
|
class NetServer : public BApplication {
|
||||||
public:
|
public:
|
||||||
NetServer();
|
NetServer();
|
||||||
@@ -41,15 +47,17 @@ class NetServer : public BApplication {
|
|||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _PrepareRequest(ifreq& request, const char* name);
|
|
||||||
bool _TestForInterface(int socket, const char* name);
|
bool _TestForInterface(int socket, const char* name);
|
||||||
status_t _ConfigureInterface(int socket, BMessage& interface);
|
status_t _ConfigureInterface(int socket, BMessage& interface);
|
||||||
|
bool _QuitLooperForDevice(const char* device);
|
||||||
|
BLooper* _LooperForDevice(const char* device);
|
||||||
status_t _ConfigureDevice(int socket, const char* path);
|
status_t _ConfigureDevice(int socket, const char* path);
|
||||||
void _ConfigureDevices(int socket, const char* path);
|
void _ConfigureDevices(int socket, const char* path);
|
||||||
void _ConfigureInterfaces(int socket);
|
void _ConfigureInterfaces(int socket);
|
||||||
void _BringUpInterfaces();
|
void _BringUpInterfaces();
|
||||||
|
|
||||||
Settings fSettings;
|
Settings fSettings;
|
||||||
|
LooperMap fDeviceMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -125,6 +133,51 @@ parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
prepare_request(ifreq& request, const char* name)
|
||||||
|
{
|
||||||
|
if (strlen(name) > IF_NAMESIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
strcpy(request.ifr_name, name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
get_mac_address(const char* device, uint8* address)
|
||||||
|
{
|
||||||
|
int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
|
||||||
|
if (socket < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
ifreq request;
|
||||||
|
if (!prepare_request(request, device)) {
|
||||||
|
close(socket);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) {
|
||||||
|
close(socket);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(socket);
|
||||||
|
|
||||||
|
sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr;
|
||||||
|
if (link.sdl_type != IFT_ETHER)
|
||||||
|
return B_BAD_TYPE;
|
||||||
|
|
||||||
|
if (link.sdl_alen == 0)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
uint8 *mac = (uint8 *)LLADDR(&link);
|
||||||
|
memcpy(address, mac, 6);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -181,6 +234,23 @@ NetServer::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case kMsgConfigureInterface:
|
||||||
|
{
|
||||||
|
if (!message->ReturnAddress().IsTargetLocal()) {
|
||||||
|
// for now, we only accept this message from add-ons
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need a socket to talk to the networking stack
|
||||||
|
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (socket < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_ConfigureInterface(socket, *message);
|
||||||
|
close(socket);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BApplication::MessageReceived(message);
|
BApplication::MessageReceived(message);
|
||||||
return;
|
return;
|
||||||
@@ -188,19 +258,6 @@ NetServer::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
NetServer::_PrepareRequest(ifreq& request, const char* name)
|
|
||||||
{
|
|
||||||
if (strlen(name) > IF_NAMESIZE) {
|
|
||||||
fprintf(stderr, "%s: interface name \"%s\" is too long.\n", Name(), name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(request.ifr_name, name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
NetServer::_TestForInterface(int socket, const char* name)
|
NetServer::_TestForInterface(int socket, const char* name)
|
||||||
{
|
{
|
||||||
@@ -254,7 +311,7 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface)
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
ifreq request;
|
ifreq request;
|
||||||
if (!_PrepareRequest(request, device))
|
if (!prepare_request(request, device))
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
int32 flags;
|
int32 flags;
|
||||||
@@ -458,20 +515,70 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetServer::_QuitLooperForDevice(const char* device)
|
||||||
|
{
|
||||||
|
LooperMap::iterator iterator = fDeviceMap.find(device);
|
||||||
|
if (iterator == fDeviceMap.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// there is a looper for this device - quit it
|
||||||
|
iterator->second->Lock();
|
||||||
|
iterator->second->Quit();
|
||||||
|
|
||||||
|
fDeviceMap.erase(iterator);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLooper*
|
||||||
|
NetServer::_LooperForDevice(const char* device)
|
||||||
|
{
|
||||||
|
LooperMap::const_iterator iterator = fDeviceMap.find(device);
|
||||||
|
if (iterator == fDeviceMap.end())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return iterator->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
NetServer::_ConfigureDevice(int socket, const char* path)
|
NetServer::_ConfigureDevice(int socket, const char* path)
|
||||||
{
|
{
|
||||||
|
_QuitLooperForDevice(path);
|
||||||
|
|
||||||
|
// bring interface up, but don't configure it just yet
|
||||||
BMessage interface;
|
BMessage interface;
|
||||||
interface.AddString("device", path);
|
interface.AddString("device", path);
|
||||||
|
|
||||||
// TODO: enable DHCP instead
|
|
||||||
BMessage address;
|
BMessage address;
|
||||||
address.AddString("family", "inet");
|
address.AddString("family", "inet");
|
||||||
address.AddString("address", "192.168.0.56");
|
|
||||||
address.AddString("gateway", "192.168.0.254");
|
|
||||||
interface.AddMessage("address", &address);
|
interface.AddMessage("address", &address);
|
||||||
|
|
||||||
return _ConfigureInterface(socket, interface);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef NET_SERVER_H
|
||||||
|
#define NET_SERVER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const uint32 kMsgConfigureInterface = 'COif';
|
||||||
|
|
||||||
|
extern bool prepare_request(ifreq& request, const char* name);
|
||||||
|
extern status_t get_mac_address(const char* device, uint8* address);
|
||||||
|
|
||||||
|
#endif // NET_SERVER_H
|
||||||
Reference in New Issue
Block a user