Added a mini networking stack to the boot loader. It speaks basic ARP,

IP, and UDP, as well as a home brewn UDP based protocol, "remote disk",
which provides random access to a single remote file/device. The Open
Firmware flavored boot loader automatically initializes the net stack,
searches for a remote disk, and tries to boot from it, if the boot
device is a network device (e.g. when loading the boot loader via
TFTP).

This is quite nice for developing with a two-machine setup, since one
doesn't even need to install Haiku on the test machine anymore, but can
serve it directly from the development machine. When the networking
support in the kernel is working, this method could even be used to
fully boot, not just for loading kernel and initial modules.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15689 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2005-12-27 22:01:33 +00:00
parent 9d577c1064
commit d561d0ad68
24 changed files with 2815 additions and 1 deletions
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_ARP_H
#define _BOOT_ARP_H
#include <boot/net/Ethernet.h>
#include <OS.h>
class ARPService : public EthernetSubService {
// actually ARP for IP over ethernet
public:
ARPService(EthernetService *ethernet);
virtual ~ARPService();
status_t Init();
virtual uint16 EthernetProtocol() const;
virtual void HandleEthernetPacket(EthernetService *ethernet,
const mac_addr_t &targetAddress, const void *data, size_t size);
status_t GetMACForIP(ip_addr_t ip, mac_addr_t &mac);
private:
enum { MAP_ENTRY_COUNT = 10 };
enum { ARP_REQUEST_RETRY_COUNT = 3 };
enum { ARP_REPLY_TIMEOUT = 5000 };
struct MapEntry {
int32 age;
ip_addr_t ip;
mac_addr_t mac;
};
status_t _SendARPPacket(ip_addr_t ip, const mac_addr_t &mac, uint16 opcode);
MapEntry *_FindEntry(ip_addr_t ip);
void _PutEntry(ip_addr_t ip, const mac_addr_t &mac);
EthernetService *fEthernet;
int32 fAge;
MapEntry fEntries[MAP_ENTRY_COUNT];
};
#endif // _BOOT_ARP_H
@@ -0,0 +1,49 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_NET_CHAIN_BUFFER_H
#define _BOOT_NET_CHAIN_BUFFER_H
#include <SupportDefs.h>
class ChainBuffer {
public:
ChainBuffer(void *data = 0, uint32 size = 0, ChainBuffer *next = NULL,
bool freeData = false);
~ChainBuffer();
void *Data() const { return fData; }
uint32 Size() const { return fSize; }
uint32 TotalSize() const { return fTotalSize; }
ChainBuffer *Next() const { return fNext; }
ChainBuffer *DetachNext();
void Append(ChainBuffer *next);
void Flatten(void *_buffer) const;
private:
// TODO: Implement Create() and Delete(). Make new and delete operators private.
enum {
CHAIN_BUFFER_HEAD = 0x1,
CHAIN_BUFFER_EMBEDDED_DATA = 0x2,
CHAIN_BUFFER_FREE_DATA = 0x4,
CHAIN_BUFFER_ON_STACK = 0x8,
};
void _Init(void *data, uint32 size, ChainBuffer *next, uint32 flags);
void _Destroy();
uint32 fFlags:4;
uint32 fSize:14;
uint32 fTotalSize:14;
void *fData;
ChainBuffer *fNext;
uint8 fBuffer[0];
};
#endif // _BOOT_NET_CHAIN_BUFFER_H
@@ -0,0 +1,84 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_ETHERNET_H
#define _BOOT_ETHERNET_H
#include <boot/net/NetDefs.h>
#include <util/Vector.h>
class ChainBuffer;
class EthernetService;
// EthernetInterface
class EthernetInterface {
public:
EthernetInterface();
virtual ~EthernetInterface();
ip_addr_t IPAddress() const;
void SetIPAddress(ip_addr_t ipAddress);
virtual mac_addr_t MACAddress() const = 0;
virtual void *AllocateSendReceiveBuffer(size_t size) = 0;
virtual void FreeSendReceiveBuffer(void *buffer) = 0;
virtual ssize_t Send(const void *buffer, size_t size) = 0;
virtual ssize_t Receive(void *buffer, size_t size) = 0;
protected:
ip_addr_t fIPAddress;
};
// EthernetSubService
class EthernetSubService : public NetService {
public:
EthernetSubService(const char *serviceName);
virtual ~EthernetSubService();
virtual uint16 EthernetProtocol() const = 0;
virtual void HandleEthernetPacket(EthernetService *ethernet,
const mac_addr_t &targetAddress, const void *data, size_t size) = 0;
};
// EthernetService
class EthernetService : public NetService {
public:
EthernetService();
virtual ~EthernetService();
status_t Init(EthernetInterface *interface);
mac_addr_t MACAddress() const;
ip_addr_t IPAddress() const;
void SetIPAddress(ip_addr_t ipAddress);
status_t Send(const mac_addr_t &destination, uint16 protocol,
ChainBuffer *buffer);
void ProcessIncomingPackets();
bool RegisterEthernetSubService(EthernetSubService *service);
bool UnregisterEthernetSubService(EthernetSubService *service);
virtual int CountSubNetServices() const;
virtual NetService *SubNetServiceAt(int index) const;
private:
enum {
SEND_BUFFER_SIZE = 2048,
RECEIVE_BUFFER_SIZE = SEND_BUFFER_SIZE,
};
EthernetInterface *fInterface;
void *fSendBuffer;
void *fReceiveBuffer;
Vector<EthernetSubService*> fServices;
};
#endif // _BOOT_ETHERNET_H
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_IP_H
#define _BOOT_IP_H
#include <boot/net/Ethernet.h>
class ARPService;
class IPService;
// IPSubService
class IPSubService : public NetService {
public:
IPSubService(const char *serviceName);
virtual ~IPSubService();
virtual uint8 IPProtocol() const = 0;
virtual void HandleIPPacket(IPService *ipService, ip_addr_t sourceIP,
ip_addr_t destinationIP, const void *data, size_t size) = 0;
};
// IPService
class IPService : public EthernetSubService {
// actually IP over ethernet
public:
IPService(EthernetService *ethernet, ARPService *arpService);
virtual ~IPService();
status_t Init();
ip_addr_t IPAddress() const;
virtual uint16 EthernetProtocol() const;
virtual void HandleEthernetPacket(EthernetService *ethernet,
const mac_addr_t &targetAddress, const void *data, size_t size);
status_t Send(ip_addr_t destination, uint8 protocol, ChainBuffer *buffer);
void ProcessIncomingPackets();
bool RegisterIPSubService(IPSubService *service);
bool UnregisterIPSubService(IPSubService *service);
virtual int CountSubNetServices() const;
virtual NetService *SubNetServiceAt(int index) const;
private:
uint16 _Checksum(const ip_header &header);
EthernetService *fEthernet;
ARPService *fARPService;
Vector<IPSubService*> fServices;
};
uint16 ip_checksum(ChainBuffer *buffer);
#endif // _BOOT_IP_H
+207
View File
@@ -0,0 +1,207 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_NET_DEFS_H
#define _BOOT_NET_DEFS_H
#include <string.h>
#include <ByteOrder.h>
#include <SupportDefs.h>
#include <util/kernel_cpp.h>
// Ethernet
#define ETH_ALEN 6
#define ETHERTYPE_IP 0x0800 // IP
#define ETHERTYPE_ARP 0x0806 // Address resolution
#define ETHER_MIN_TRANSFER_UNIT 46
#define ETHER_MAX_TRANSFER_UNIT 1500
struct mac_addr_t {
mac_addr_t() {}
mac_addr_t(uint8 *address)
{
memcpy(this->address, address, ETH_ALEN);
}
mac_addr_t(const mac_addr_t& other)
{
memcpy(address, other.address, sizeof(address));
}
uint64 ToUInt64() const
{
return ((uint64)address[0] << 40)
| ((uint64)address[1] << 32)
| ((uint64)address[2] << 24)
| ((uint64)address[3] << 16)
| ((uint64)address[4] << 8)
| (uint64)address[5];
}
mac_addr_t& operator=(const mac_addr_t& other)
{
memcpy(address, other.address, sizeof(address));
return *this;
}
bool operator==(const mac_addr_t& other) const
{
return memcmp(address, other.address, sizeof(address)) == 0;
}
bool operator!=(const mac_addr_t& other) const
{
return !(*this == other);
}
uint8 address[ETH_ALEN];
} __attribute__ ((__packed__));
extern const mac_addr_t kBroadcastMACAddress;
extern const mac_addr_t kNoMACAddress;
// 10/100 Mb/s ethernet header
struct ether_header {
mac_addr_t destination; /* destination eth addr */
mac_addr_t source; /* source ether addr */
uint16 type; /* packet type ID field */
} __attribute__ ((__packed__));
// #pragma mark -
// Address Resolution Protocol (ARP)
typedef uint32 ip_addr_t;
// ARP protocol opcodes
#define ARPOP_REQUEST 1 /* ARP request. */
#define ARPOP_REPLY 2 /* ARP reply. */
#define ARPOP_RREQUEST 3 /* RARP request. */
#define ARPOP_RREPLY 4 /* RARP reply. */
#define ARPOP_InREQUEST 8 /* InARP request. */
#define ARPOP_InREPLY 9 /* InARP reply. */
#define ARPOP_NAK 10 /* (ATM)ARP NAK. */
// ARP header for IP over ethernet (RFC 826)
struct arp_header {
uint16 hardware_format; /* Format of hardware address. */
uint16 protocol_format; /* Format of protocol address. */
uint8 hardware_length; /* Length of hardware address. */
uint8 protocol_length; /* Length of protocol address. */
uint16 opcode; /* ARP opcode (command). */
// IP over ethernet
mac_addr_t sender_mac; /* Sender hardware address. */
ip_addr_t sender_ip; /* Sender IP address. */
mac_addr_t target_mac; /* Target hardware address. */
ip_addr_t target_ip; /* Target IP address. */
} __attribute__ ((__packed__));
// ARP protocol HARDWARE identifiers.
#define ARPHRD_ETHER 1 /* Ethernet 10/100Mbps. */
// #pragma mark -
// Internet Protocol (IP)
#define INADDR_ANY ((ip_addr_t) 0x00000000)
/* Address to send to all hosts. */
#define INADDR_BROADCAST ((ip_addr_t) 0xffffffff)
/* Address indicating an error return. */
#define INADDR_NONE ((ip_addr_t) 0xffffffff)
// IP packet header (no options
struct ip_header {
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8 header_length:4; // header length
uint8 version:4; // IP protocol version
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
uint8 version:4; // IP protocol version
uint8 header_length:4; // header length
#endif
uint8 type_of_service; // type of service
uint16 total_length; // total IP packet length
uint16 identifier; // fragment identification
uint16 fragment_offset; // fragment offset and flags (0xe000)
uint8 time_to_live; // time to live
uint8 protocol; // protocol
uint16 checksum; // checksum (header)
ip_addr_t source; // source IP address
ip_addr_t destination; // destination IP address
} __attribute__ ((__packed__));
// IP protocol version 4
#define IP_PROTOCOL_VERSION_4 4
// fragment flags/offset mask
#define IP_DONT_FRAGMENT 0x4000 /* dont fragment flag */
#define IP_FRAGMENT_OFFSET_MASK 0x1fff /* mask for fragment offset */
// Internet implementation parameters.
#define IP_MAX_TIME_TO_LIVE 255 /* maximum time to live */
#define IP_DEFAULT_TIME_TO_LIVE 64 /* default ttl, from RFC 1340 */
// IP protocols
#define IPPROTO_UDP 17
// #pragma mark -
// User Datagram Protocol (UDP)
// UDP header (RFC 768)
struct udp_header
{
uint16 source; // source port
uint16 destination; // destination port
uint16 length; // length of UDP packet (header + data)
uint16 checksum; // checksum
} __attribute__ ((__packed__));
// #pragma mark -
// NetService
// net service names
extern const char *const kEthernetServiceName;
extern const char *const kARPServiceName;
extern const char *const kIPServiceName;
extern const char *const kUDPServiceName;
class NetService {
public:
NetService(const char *name);
virtual ~NetService();
const char *NetServiceName();
virtual int CountSubNetServices() const;
virtual NetService *SubNetServiceAt(int index) const;
virtual NetService *FindSubNetService(const char *name) const;
template<typename ServiceType>
ServiceType *FindSubNetService(const char *name) const
{
// We should actually use dynamic_cast<>(), but we better spare us the
// RTTI stuff.
if (NetService *service = FindSubNetService(name))
return static_cast<ServiceType*>(service);
return NULL;
}
private:
const char *fName;
};
#endif // _BOOT_NET_DEFS_H
@@ -0,0 +1,55 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_NET_STACK_H
#define _BOOT_NET_STACK_H
#include <SupportDefs.h>
class EthernetInterface;
class EthernetService;
class ARPService;
class IPService;
class UDPService;
class NetStack {
private:
NetStack();
~NetStack();
status_t Init();
public:
static status_t CreateDefault();
static NetStack *Default();
status_t AddEthernetInterface(EthernetInterface *interface);
EthernetInterface *GetEthernetInterface() const
{ return fEthernetInterface; }
EthernetService *GetEthernetService() const { return fEthernetService; }
ARPService *GetARPService() const { return fARPService; }
IPService *GetIPService() const { return fIPService; }
UDPService *GetUDPService() const { return fUDPService; }
private:
static NetStack *sNetStack;
EthernetInterface *fEthernetInterface;
EthernetService *fEthernetService;
ARPService *fARPService;
IPService *fIPService;
UDPService *fUDPService;
};
// net_stack_init() creates the NetStack and calls platform_net_stack_init()
// afterwards, which is supposed to add network interfaces.
status_t net_stack_init();
status_t platform_net_stack_init();
#endif // _BOOT_NET_STACK_H
@@ -0,0 +1,51 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_REMOTE_DISK_H
#define _BOOT_REMOTE_DISK_H
#include <boot/vfs.h>
#include <boot/net/NetDefs.h>
#include <boot/net/RemoteDiskDefs.h>
class UDPPacket;
class UDPSocket;
class RemoteDisk : public Node {
public:
RemoteDisk();
~RemoteDisk();
status_t Init(ip_addr_t serverAddress, uint16 serverPort, off_t imageSize);
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
size_t bufferSize);
virtual status_t GetName(char *nameBuffer, size_t bufferSize) const;
virtual off_t Size() const;
static RemoteDisk *FindAnyRemoteDisk();
private:
ssize_t _ReadFromPacket(off_t &pos, uint8 *&buffer, size_t &bufferSize);
static status_t _SendRequest(UDPSocket *socket, ip_addr_t serverAddress,
uint16 serverPort, remote_disk_header *request, size_t size,
uint8 expectedReply, UDPPacket **packet);
status_t _SendRequest(remote_disk_header *request, size_t size,
uint8 expectedReply, UDPPacket **packet);
private:
ip_addr_t fServerAddress;
uint16 fServerPort;
off_t fImageSize;
uint64 fRequestID;
UDPSocket *fSocket;
UDPPacket *fPacket;
};
#endif // _BOOT_REMOTE_DISK_H
@@ -0,0 +1,63 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_REMOTE_DISK_DEFS_H
#define _BOOT_REMOTE_DISK_DEFS_H
#include <stdint.h>
enum {
REMOTE_DISK_SERVER_PORT = 8765,
REMOTE_DISK_BLOCK_SIZE = 1024,
};
enum {
// requests
REMOTE_DISK_HELLO_REQUEST = 0,
// port: client port
REMOTE_DISK_READ_REQUEST = 1,
// port: client port
// offset: byte offset of data to read
// size: number of bytes to read (server might serve more, though)
REMOTE_DISK_WRITE_REQUEST = 2,
// port: client port
// offset: byte offset of data to write
// size: number of bytes to write
// data: the data
// replies
REMOTE_DISK_HELLO_REPLY = 3,
// offset: disk size
REMOTE_DISK_READ_REPLY = 4, // port unused
// offset: byte offset of read data
// size: number of bytes of data read; < 0 => error
// data: read data
REMOTE_DISK_WRITE_REPLY = 5, // port, data unused
// offset: byte offset of data written
// size: number of bytes of data written; < 0 => error
};
// errors
enum {
REMOTE_DISK_IO_ERROR = -1,
REMOTE_DISK_BAD_REQUEST = -2,
};
struct remote_disk_header {
uint64_t offset;
uint64_t request_id;
int16_t size;
uint16_t port;
uint8_t command;
uint8_t data[0];
} __attribute__ ((__packed__));
#endif // _BOOT_REMOTE_DISK_DEFS_H
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright 2005, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BOOT_UDP_H
#define _BOOT_UDP_H
#include <boot/net/IP.h>
// UDPPacket
class UDPPacket {
public:
UDPPacket();
~UDPPacket();
status_t SetTo(const void *data, size_t size, ip_addr_t sourceAddress,
uint16 sourcePort, ip_addr_t destinationAddress,
uint16 destinationPort);
UDPPacket *Next() const;
void SetNext(UDPPacket *next);
const void *Data() const;
size_t DataSize() const;
ip_addr_t SourceAddress() const;
uint16 SourcePort() const;
ip_addr_t DestinationAddress() const;
uint16 DestinationPort() const;
private:
UDPPacket *fNext;
void *fData;
size_t fSize;
ip_addr_t fSourceAddress;
ip_addr_t fDestinationAddress;
uint16 fSourcePort;
uint16 fDestinationPort;
};
class UDPService;
// UDPSocket
class UDPSocket {
public:
UDPSocket();
~UDPSocket();
ip_addr_t Address() const { return fAddress; }
uint16 Port() const { return fPort; }
status_t Bind(ip_addr_t address, uint16 port);
status_t Send(ip_addr_t destinationAddress, uint16 destinationPort,
ChainBuffer *buffer);
status_t Send(ip_addr_t destinationAddress, uint16 destinationPort,
const void *data, size_t size);
status_t Receive(UDPPacket **packet, bigtime_t timeout = 0);
void PushPacket(UDPPacket *packet);
UDPPacket *PopPacket();
private:
UDPService *fUDPService;
UDPPacket *fFirstPacket;
UDPPacket *fLastPacket;
ip_addr_t fAddress;
uint16 fPort;
};
// UDPService
class UDPService : public IPSubService {
public:
UDPService(IPService *ipService);
virtual ~UDPService();
status_t Init();
virtual uint8 IPProtocol() const;
virtual void HandleIPPacket(IPService *ipService, ip_addr_t sourceIP,
ip_addr_t destinationIP, const void *data, size_t size);
status_t Send(uint16 sourcePort, ip_addr_t destinationAddress,
uint16 destinationPort, ChainBuffer *buffer);
void ProcessIncomingPackets();
status_t BindSocket(UDPSocket *socket, ip_addr_t address, uint16 port);
void UnbindSocket(UDPSocket *socket);
private:
uint16 _ChecksumBuffer(ChainBuffer *buffer, ip_addr_t source,
ip_addr_t destination, uint16 length);
uint16 _ChecksumData(const void *data, uint16 length, ip_addr_t source,
ip_addr_t destination);
UDPSocket *_FindSocket(ip_addr_t address, uint16 port);
IPService *fIPService;
Vector<UDPSocket*> fSockets;
};
#endif // _BOOT_UDP_H