1d561d0adSIngo Weinhold /* 2d561d0adSIngo Weinhold * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3d561d0adSIngo Weinhold * All rights reserved. Distributed under the terms of the MIT License. 4d561d0adSIngo Weinhold */ 5d561d0adSIngo Weinhold 6d561d0adSIngo Weinhold #include <new> 7d561d0adSIngo Weinhold 8d561d0adSIngo Weinhold #include <stdio.h> 9d561d0adSIngo Weinhold #include <stdlib.h> 10d561d0adSIngo Weinhold #include <string.h> 11d561d0adSIngo Weinhold 12d561d0adSIngo Weinhold #include <OS.h> 13d561d0adSIngo Weinhold 14d561d0adSIngo Weinhold #include <boot/net/Ethernet.h> 15d561d0adSIngo Weinhold #include <boot/net/NetStack.h> 16*957a1b17SIngo Weinhold #include <platform/openfirmware/openfirmware.h> 17d561d0adSIngo Weinhold 18d561d0adSIngo Weinhold 19d561d0adSIngo Weinhold //#define TRACE_NETWORK 20d561d0adSIngo Weinhold #ifdef TRACE_NETWORK 21d561d0adSIngo Weinhold # define TRACE(x) dprintf x 22d561d0adSIngo Weinhold #else 23d561d0adSIngo Weinhold # define TRACE(x) ; 24d561d0adSIngo Weinhold #endif 25d561d0adSIngo Weinhold 26d561d0adSIngo Weinhold 27d561d0adSIngo Weinhold #ifdef TRACE_NETWORK 28d561d0adSIngo Weinhold 29d561d0adSIngo Weinhold static void 30d561d0adSIngo Weinhold hex_dump(const void *_data, int length) 31d561d0adSIngo Weinhold { 32d561d0adSIngo Weinhold uint8 *data = (uint8*)_data; 33d561d0adSIngo Weinhold for (int i = 0; i < length; i++) { 34d561d0adSIngo Weinhold if (i % 4 == 0) { 35d561d0adSIngo Weinhold if (i % 32 == 0) { 36d561d0adSIngo Weinhold if (i != 0) 37d561d0adSIngo Weinhold printf("\n"); 38d561d0adSIngo Weinhold printf("%03x: ", i); 39d561d0adSIngo Weinhold } else 40d561d0adSIngo Weinhold printf(" "); 41d561d0adSIngo Weinhold } 42d561d0adSIngo Weinhold 43d561d0adSIngo Weinhold printf("%02x", data[i]); 44d561d0adSIngo Weinhold } 45d561d0adSIngo Weinhold printf("\n"); 46d561d0adSIngo Weinhold } 47d561d0adSIngo Weinhold 48d561d0adSIngo Weinhold #else // !TRACE_NETWORK 49d561d0adSIngo Weinhold 50d561d0adSIngo Weinhold #define hex_dump(data, length) 51d561d0adSIngo Weinhold 52d561d0adSIngo Weinhold #endif // !TRACE_NETWORK 53d561d0adSIngo Weinhold 54d561d0adSIngo Weinhold 55d561d0adSIngo Weinhold class OFEthernetInterface : public EthernetInterface { 56d561d0adSIngo Weinhold public: 57d561d0adSIngo Weinhold OFEthernetInterface(); 58d561d0adSIngo Weinhold virtual ~OFEthernetInterface(); 59d561d0adSIngo Weinhold 60d561d0adSIngo Weinhold status_t Init(const char *device); 61d561d0adSIngo Weinhold 62d561d0adSIngo Weinhold virtual mac_addr_t MACAddress() const; 63d561d0adSIngo Weinhold 64d561d0adSIngo Weinhold virtual void *AllocateSendReceiveBuffer(size_t size); 65d561d0adSIngo Weinhold virtual void FreeSendReceiveBuffer(void *buffer); 66d561d0adSIngo Weinhold 67d561d0adSIngo Weinhold virtual ssize_t Send(const void *buffer, size_t size); 68d561d0adSIngo Weinhold virtual ssize_t Receive(void *buffer, size_t size); 69d561d0adSIngo Weinhold 70d561d0adSIngo Weinhold private: 71d561d0adSIngo Weinhold int fHandle; 72d561d0adSIngo Weinhold mac_addr_t fMACAddress; 73d561d0adSIngo Weinhold }; 74d561d0adSIngo Weinhold 75d561d0adSIngo Weinhold // constructor 76d561d0adSIngo Weinhold OFEthernetInterface::OFEthernetInterface() 77d561d0adSIngo Weinhold : EthernetInterface(), 78d561d0adSIngo Weinhold fHandle(OF_FAILED), 79d561d0adSIngo Weinhold fMACAddress(kNoMACAddress) 80d561d0adSIngo Weinhold { 81d561d0adSIngo Weinhold } 82d561d0adSIngo Weinhold 83d561d0adSIngo Weinhold // destructor 84d561d0adSIngo Weinhold OFEthernetInterface::~OFEthernetInterface() 85d561d0adSIngo Weinhold { 86d561d0adSIngo Weinhold if (fHandle != OF_FAILED) 87d561d0adSIngo Weinhold of_close(fHandle); 88d561d0adSIngo Weinhold } 89d561d0adSIngo Weinhold 90d561d0adSIngo Weinhold // Init 91d561d0adSIngo Weinhold status_t 92d561d0adSIngo Weinhold OFEthernetInterface::Init(const char *device) 93d561d0adSIngo Weinhold { 94d561d0adSIngo Weinhold if (!device) 95d561d0adSIngo Weinhold return B_BAD_VALUE; 96d561d0adSIngo Weinhold 97d561d0adSIngo Weinhold // open device 98d561d0adSIngo Weinhold fHandle = of_open(device); 99d561d0adSIngo Weinhold if (fHandle == OF_FAILED) { 100d561d0adSIngo Weinhold printf("opening ethernet device failed\n"); 101d561d0adSIngo Weinhold return B_ERROR; 102d561d0adSIngo Weinhold } 103d561d0adSIngo Weinhold 104d561d0adSIngo Weinhold int package = of_instance_to_package(fHandle); 105d561d0adSIngo Weinhold 106d561d0adSIngo Weinhold // get MAC address 107d561d0adSIngo Weinhold int bytesRead = of_getprop(package, "local-mac-address", &fMACAddress, 108d561d0adSIngo Weinhold sizeof(fMACAddress)); 109d561d0adSIngo Weinhold if (bytesRead == OF_FAILED || bytesRead < (int)sizeof(fMACAddress)) { 110d561d0adSIngo Weinhold // Failed to get the MAC address of the network device. The system may 111d561d0adSIngo Weinhold // have a global standard MAC address. 112d561d0adSIngo Weinhold bytesRead = of_getprop(gChosen, "mac-address", &fMACAddress, 113d561d0adSIngo Weinhold sizeof(fMACAddress)); 114d561d0adSIngo Weinhold if (bytesRead == OF_FAILED || bytesRead < (int)sizeof(fMACAddress)) { 115d561d0adSIngo Weinhold printf("Failed to get MAC address\n"); 116d561d0adSIngo Weinhold return B_ERROR; 117d561d0adSIngo Weinhold } 118d561d0adSIngo Weinhold } 119d561d0adSIngo Weinhold 120d561d0adSIngo Weinhold // get IP address 121d561d0adSIngo Weinhold // Note: This is a non-standardized way. On my Mac mini the response of the 122d561d0adSIngo Weinhold // DHCP server is stored as property of /chosen. We try to get that it and 123d561d0adSIngo Weinhold // use the IP address we find in there. 124d561d0adSIngo Weinhold struct { 125d561d0adSIngo Weinhold uint8 irrelevant[16]; 126d561d0adSIngo Weinhold uint32 ip_address; 127d561d0adSIngo Weinhold // ... 128d561d0adSIngo Weinhold } dhcpResponse; 129d561d0adSIngo Weinhold bytesRead = of_getprop(gChosen, "dhcp-response", &dhcpResponse, 130d561d0adSIngo Weinhold sizeof(dhcpResponse)); 131d561d0adSIngo Weinhold if (bytesRead != OF_FAILED && bytesRead == (int)sizeof(dhcpResponse)) 132d561d0adSIngo Weinhold SetIPAddress(ntohl(dhcpResponse.ip_address)); 133d561d0adSIngo Weinhold 134d561d0adSIngo Weinhold return B_OK; 135d561d0adSIngo Weinhold } 136d561d0adSIngo Weinhold 137d561d0adSIngo Weinhold // MACAddress 138d561d0adSIngo Weinhold mac_addr_t 139d561d0adSIngo Weinhold OFEthernetInterface::MACAddress() const 140d561d0adSIngo Weinhold { 141d561d0adSIngo Weinhold return fMACAddress; 142d561d0adSIngo Weinhold } 143d561d0adSIngo Weinhold 144d561d0adSIngo Weinhold // AllocateSendReceiveBuffer 145d561d0adSIngo Weinhold void * 146d561d0adSIngo Weinhold OFEthernetInterface::AllocateSendReceiveBuffer(size_t size) 147d561d0adSIngo Weinhold { 148d561d0adSIngo Weinhold void *dmaMemory; 149d561d0adSIngo Weinhold if (of_call_method(fHandle, "dma-alloc", 1, 1, size, &dmaMemory) 150d561d0adSIngo Weinhold == OF_FAILED) { 151d561d0adSIngo Weinhold return NULL; 152d561d0adSIngo Weinhold } 153d561d0adSIngo Weinhold return dmaMemory; 154d561d0adSIngo Weinhold } 155d561d0adSIngo Weinhold 156d561d0adSIngo Weinhold // FreeSendReceiveBuffer 157d561d0adSIngo Weinhold void 158d561d0adSIngo Weinhold OFEthernetInterface::FreeSendReceiveBuffer(void *buffer) 159d561d0adSIngo Weinhold { 160d561d0adSIngo Weinhold if (buffer) 161d561d0adSIngo Weinhold of_call_method(fHandle, "dma-free", 1, 0, buffer); 162d561d0adSIngo Weinhold } 163d561d0adSIngo Weinhold 164d561d0adSIngo Weinhold // Send 165d561d0adSIngo Weinhold ssize_t 166d561d0adSIngo Weinhold OFEthernetInterface::Send(const void *buffer, size_t size) 167d561d0adSIngo Weinhold { 168d561d0adSIngo Weinhold TRACE(("OFEthernetInterface::Send(%p, %lu)\n", buffer, size)); 169d561d0adSIngo Weinhold 170d561d0adSIngo Weinhold if (!buffer) 171d561d0adSIngo Weinhold return B_BAD_VALUE; 172d561d0adSIngo Weinhold 173d561d0adSIngo Weinhold hex_dump(buffer, size); 174d561d0adSIngo Weinhold 175d561d0adSIngo Weinhold int result = of_write(fHandle, buffer, size); 176d561d0adSIngo Weinhold return (result == OF_FAILED ? B_ERROR : result); 177d561d0adSIngo Weinhold } 178d561d0adSIngo Weinhold 179d561d0adSIngo Weinhold // Receive 180d561d0adSIngo Weinhold ssize_t 181d561d0adSIngo Weinhold OFEthernetInterface::Receive(void *buffer, size_t size) 182d561d0adSIngo Weinhold { 183d561d0adSIngo Weinhold if (!buffer) 184d561d0adSIngo Weinhold return B_BAD_VALUE; 185d561d0adSIngo Weinhold 186d561d0adSIngo Weinhold int result = of_read(fHandle, buffer, size); 187d561d0adSIngo Weinhold 188d561d0adSIngo Weinhold if (result != OF_FAILED && result >= 0) { 189d561d0adSIngo Weinhold TRACE(("OFEthernetInterface::Receive(%p, %lu): received %d bytes\n", 190d561d0adSIngo Weinhold buffer, size, result)); 191d561d0adSIngo Weinhold hex_dump(buffer, result); 192d561d0adSIngo Weinhold } 193d561d0adSIngo Weinhold 194d561d0adSIngo Weinhold return (result == OF_FAILED ? B_ERROR : result); 195d561d0adSIngo Weinhold } 196d561d0adSIngo Weinhold 197d561d0adSIngo Weinhold 198d561d0adSIngo Weinhold // #pragma mark - 199d561d0adSIngo Weinhold 200d561d0adSIngo Weinhold // platform_net_stack_init 201d561d0adSIngo Weinhold status_t 202d561d0adSIngo Weinhold platform_net_stack_init() 203d561d0adSIngo Weinhold { 204d561d0adSIngo Weinhold // Note: At the moment we only do networking at all, if the boot device 205d561d0adSIngo Weinhold // is a network device. If it isn't, we simply fail here. For serious 206d561d0adSIngo Weinhold // support we would want to iterate through the device tree and add all 207d561d0adSIngo Weinhold // network devices. 208d561d0adSIngo Weinhold 209d561d0adSIngo Weinhold // get boot path 210d561d0adSIngo Weinhold char bootPath[192]; 211d561d0adSIngo Weinhold int length = of_getprop(gChosen, "bootpath", bootPath, sizeof(bootPath)); 212d561d0adSIngo Weinhold if (length <= 1) 213d561d0adSIngo Weinhold return B_ERROR; 214d561d0adSIngo Weinhold 215d561d0adSIngo Weinhold // we chop off parameters; otherwise opening the network device might have 216d561d0adSIngo Weinhold // side effects 217d561d0adSIngo Weinhold char *lastComponent = strrchr(bootPath, '/'); 218d561d0adSIngo Weinhold char *parameters = strchr((lastComponent ? lastComponent : bootPath), ':'); 219d561d0adSIngo Weinhold if (parameters) 220d561d0adSIngo Weinhold *parameters = '\0'; 221d561d0adSIngo Weinhold 222d561d0adSIngo Weinhold // get device node 223d561d0adSIngo Weinhold int node = of_finddevice(bootPath); 224d561d0adSIngo Weinhold if (node == OF_FAILED) 225d561d0adSIngo Weinhold return B_ERROR; 226d561d0adSIngo Weinhold 227d561d0adSIngo Weinhold // get device type 228d561d0adSIngo Weinhold char type[16]; 229d561d0adSIngo Weinhold if (of_getprop(node, "device_type", type, sizeof(type)) == OF_FAILED 230d561d0adSIngo Weinhold || strcmp("network", type) != 0) { 231d561d0adSIngo Weinhold return B_ERROR; 232d561d0adSIngo Weinhold } 233d561d0adSIngo Weinhold 234d561d0adSIngo Weinhold // create an EthernetInterface object for the device 235d561d0adSIngo Weinhold OFEthernetInterface *interface = new(nothrow) OFEthernetInterface; 236d561d0adSIngo Weinhold if (!interface) 237d561d0adSIngo Weinhold return B_NO_MEMORY; 238d561d0adSIngo Weinhold 239d561d0adSIngo Weinhold status_t error = interface->Init(bootPath); 240d561d0adSIngo Weinhold if (error != B_OK) { 241d561d0adSIngo Weinhold delete interface; 242d561d0adSIngo Weinhold return error; 243d561d0adSIngo Weinhold } 244d561d0adSIngo Weinhold 245d561d0adSIngo Weinhold // add it to the net stack 246d561d0adSIngo Weinhold error = NetStack::Default()->AddEthernetInterface(interface); 247d561d0adSIngo Weinhold if (error != B_OK) { 248d561d0adSIngo Weinhold delete interface; 249d561d0adSIngo Weinhold return error; 250d561d0adSIngo Weinhold } 251d561d0adSIngo Weinhold 252d561d0adSIngo Weinhold return B_OK; 253d561d0adSIngo Weinhold } 254