* Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* Copyright 2010, Andreas Faerber <andreas.faerber@web.de>
* Copyright 2002, Adrien Destugues <pulkomandy@pulkomandy.tk>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <OS.h>
#include <boot/platform.h>
#include <boot/net/Ethernet.h>
#include <boot/net/IP.h>
#include <boot/net/NetStack.h>
#include <platform/openfirmware/openfirmware.h>
#ifdef TRACE_NETWORK
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
class OFEthernetInterface : public EthernetInterface {
public:
OFEthernetInterface();
virtual ~OFEthernetInterface();
status_t Init(const char *device, const char *parameters);
virtual mac_addr_t MACAddress() const;
virtual void * AllocateSendReceiveBuffer(size_t size);
virtual void FreeSendReceiveBuffer(void *buffer);
virtual ssize_t Send(const void *buffer, size_t size);
virtual ssize_t Receive(void *buffer, size_t size);
private:
status_t FindMACAddress();
private:
intptr_t fHandle;
mac_addr_t fMACAddress;
};
#ifdef TRACE_NETWORK
static void
hex_dump(const void *_data, int length)
{
uint8 *data = (uint8*)_data;
for (int i = 0; i < length; i++) {
if (i % 4 == 0) {
if (i % 32 == 0) {
if (i != 0)
printf("\n");
printf("%03x: ", i);
} else
printf(" ");
}
printf("%02x", data[i]);
}
printf("\n");
}
#else
#define hex_dump(data, length)
#endif
OFEthernetInterface::OFEthernetInterface()
:
EthernetInterface(),
fHandle(OF_FAILED),
fMACAddress(kNoMACAddress)
{
}
OFEthernetInterface::~OFEthernetInterface()
{
if (fHandle != OF_FAILED)
of_close(fHandle);
}
status_t
OFEthernetInterface::FindMACAddress()
{
intptr_t package = of_instance_to_package(fHandle);
int bytesRead = of_getprop(package, "local-mac-address", &fMACAddress,
sizeof(fMACAddress));
if (bytesRead == (int)sizeof(fMACAddress))
return B_OK;
bytesRead = of_getprop(gChosen, "mac-address", &fMACAddress,
sizeof(fMACAddress));
if (bytesRead == (int)sizeof(fMACAddress)) {
return B_OK;
}
size_t size;
void* ptr;
if (of_interpret("mac-address", 0, 2, &size, &ptr) != OF_FAILED) {
if (size == sizeof(fMACAddress)) {
memcpy(&fMACAddress, ptr, size);
return B_OK;
}
}
return B_ERROR;
}
status_t
OFEthernetInterface::Init(const char *device, const char *parameters)
{
if (!device)
return B_BAD_VALUE;
fHandle = of_open(device);
if (fHandle == OF_FAILED) {
printf("opening ethernet device failed\n");
return B_ERROR;
}
if (FindMACAddress() != B_OK) {
printf("Failed to get MAC address\n");
return B_ERROR;
}
struct {
uint8 irrelevant[16];
uint32 ip_address;
} dhcpResponse;
int bytesRead = of_getprop(gChosen, "dhcp-response", &dhcpResponse,
sizeof(dhcpResponse));
if (bytesRead != OF_FAILED && bytesRead == (int)sizeof(dhcpResponse)) {
SetIPAddress(ntohl(dhcpResponse.ip_address));
return B_OK;
}
if (parameters != NULL) {
char *comma = strrchr(parameters, ',');
if (comma != NULL && comma != strchr(parameters, ',')) {
SetIPAddress(ip_parse_address(comma + 1));
return B_OK;
}
}
char defaultClientIP[16];
intptr_t package = of_finddevice("/options");
bytesRead = of_getprop(package, "default-client-ip",
defaultClientIP, sizeof(defaultClientIP) - 1);
if (bytesRead != OF_FAILED && bytesRead > 1) {
defaultClientIP[bytesRead] = '\0';
ip_addr_t address = ip_parse_address(defaultClientIP);
SetIPAddress(address);
return B_OK;
}
return B_ERROR;
}
mac_addr_t
OFEthernetInterface::MACAddress() const
{
return fMACAddress;
}
void *
OFEthernetInterface::AllocateSendReceiveBuffer(size_t size)
{
void *dmaMemory = NULL;
if (of_call_method(fHandle, "dma-alloc", 1, 1, size, &dmaMemory)
!= OF_FAILED) {
return dmaMemory;
}
intptr_t parentPackage = of_parent(of_instance_to_package(fHandle));
char path[256];
of_package_to_path(parentPackage, path, sizeof(path));
intptr_t parentInstance = of_open(path);
if (of_call_method(parentInstance, "dma-alloc", 1, 1, size, &dmaMemory)
!= OF_FAILED) {
of_close(parentInstance);
return dmaMemory;
}
of_close(parentInstance);
return NULL;
}
void
OFEthernetInterface::FreeSendReceiveBuffer(void *buffer)
{
if (buffer)
of_call_method(fHandle, "dma-free", 1, 0, buffer);
}
ssize_t
OFEthernetInterface::Send(const void *buffer, size_t size)
{
TRACE(("OFEthernetInterface::Send(%p, %lu)\n", buffer, size));
if (!buffer)
return B_BAD_VALUE;
hex_dump(buffer, size);
int result = of_write(fHandle, buffer, size);
return (result == OF_FAILED ? B_ERROR : result);
}
ssize_t
OFEthernetInterface::Receive(void *buffer, size_t size)
{
if (!buffer)
return B_BAD_VALUE;
int result = of_read(fHandle, buffer, size);
if (result != OF_FAILED && result >= 0) {
TRACE(("OFEthernetInterface::Receive(%p, %lu): received %d bytes\n",
buffer, size, result));
hex_dump(buffer, result);
}
return (result == OF_FAILED ? B_ERROR : result);
}
status_t
platform_net_stack_init()
{
char bootPath[192];
int length = of_getprop(gChosen, "bootpath", bootPath, sizeof(bootPath));
if (length <= 1)
return B_ERROR;
char *lastComponent = strrchr(bootPath, '/');
char *parameters = strchr((lastComponent ? lastComponent : bootPath), ':');
if (parameters)
*parameters = '\0';
intptr_t node = of_finddevice(bootPath);
if (node == OF_FAILED)
return B_ERROR;
char type[16];
if (of_getprop(node, "device_type", type, sizeof(type)) == OF_FAILED
|| strcmp("network", type) != 0) {
return B_ERROR;
}
OFEthernetInterface *interface = new(nothrow) OFEthernetInterface;
if (!interface)
return B_NO_MEMORY;
status_t error = interface->Init(bootPath, parameters + 1);
if (error != B_OK) {
delete interface;
return error;
}
error = NetStack::Default()->AddEthernetInterface(interface);
if (error != B_OK) {
delete interface;
return error;
}
return B_OK;
}