1d561d0adSIngo Weinhold /* 2d561d0adSIngo Weinhold * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 37c5a2487SStephan Aßmus * Copyright 2010, Andreas Faerber <andreas.faerber@web.de> 4d561d0adSIngo Weinhold * All rights reserved. Distributed under the terms of the MIT License. 5d561d0adSIngo Weinhold */ 6d561d0adSIngo Weinhold 7e0d09e23SAxel Dörfler 8d561d0adSIngo Weinhold #include <new> 9d561d0adSIngo Weinhold 10d561d0adSIngo Weinhold #include <stdio.h> 11d561d0adSIngo Weinhold #include <stdlib.h> 12d561d0adSIngo Weinhold #include <string.h> 13d561d0adSIngo Weinhold 14d561d0adSIngo Weinhold #include <OS.h> 15d561d0adSIngo Weinhold 16e355ce92SStephan Aßmus #include <boot/platform.h> 17d561d0adSIngo Weinhold #include <boot/net/Ethernet.h> 1863b69becSAxel Dörfler #include <boot/net/IP.h> 19d561d0adSIngo Weinhold #include <boot/net/NetStack.h> 20957a1b17SIngo Weinhold #include <platform/openfirmware/openfirmware.h> 21d561d0adSIngo Weinhold 22d561d0adSIngo Weinhold 23d561d0adSIngo Weinhold //#define TRACE_NETWORK 24d561d0adSIngo Weinhold #ifdef TRACE_NETWORK 25d561d0adSIngo Weinhold # define TRACE(x) dprintf x 26d561d0adSIngo Weinhold #else 27d561d0adSIngo Weinhold # define TRACE(x) ; 28d561d0adSIngo Weinhold #endif 29d561d0adSIngo Weinhold 30d561d0adSIngo Weinhold 31e0d09e23SAxel Dörfler class OFEthernetInterface : public EthernetInterface { 32e0d09e23SAxel Dörfler public: 33e0d09e23SAxel Dörfler OFEthernetInterface(); 34e0d09e23SAxel Dörfler virtual ~OFEthernetInterface(); 35e0d09e23SAxel Dörfler 367c5a2487SStephan Aßmus status_t Init(const char *device, const char *parameters); 37e0d09e23SAxel Dörfler 38e0d09e23SAxel Dörfler virtual mac_addr_t MACAddress() const; 39e0d09e23SAxel Dörfler 40e0d09e23SAxel Dörfler virtual void *AllocateSendReceiveBuffer(size_t size); 41e0d09e23SAxel Dörfler virtual void FreeSendReceiveBuffer(void *buffer); 42e0d09e23SAxel Dörfler 43e0d09e23SAxel Dörfler virtual ssize_t Send(const void *buffer, size_t size); 44e0d09e23SAxel Dörfler virtual ssize_t Receive(void *buffer, size_t size); 45e0d09e23SAxel Dörfler 46e0d09e23SAxel Dörfler private: 47*95958839SPulkoMandy intptr_t fHandle; 48e0d09e23SAxel Dörfler mac_addr_t fMACAddress; 49e0d09e23SAxel Dörfler }; 50e0d09e23SAxel Dörfler 51e0d09e23SAxel Dörfler 52d561d0adSIngo Weinhold #ifdef TRACE_NETWORK 53d561d0adSIngo Weinhold 54d561d0adSIngo Weinhold static void 55d561d0adSIngo Weinhold hex_dump(const void *_data, int length) 56d561d0adSIngo Weinhold { 57d561d0adSIngo Weinhold uint8 *data = (uint8*)_data; 58d561d0adSIngo Weinhold for (int i = 0; i < length; i++) { 59d561d0adSIngo Weinhold if (i % 4 == 0) { 60d561d0adSIngo Weinhold if (i % 32 == 0) { 61d561d0adSIngo Weinhold if (i != 0) 62d561d0adSIngo Weinhold printf("\n"); 63d561d0adSIngo Weinhold printf("%03x: ", i); 64d561d0adSIngo Weinhold } else 65d561d0adSIngo Weinhold printf(" "); 66d561d0adSIngo Weinhold } 67d561d0adSIngo Weinhold 68d561d0adSIngo Weinhold printf("%02x", data[i]); 69d561d0adSIngo Weinhold } 70d561d0adSIngo Weinhold printf("\n"); 71d561d0adSIngo Weinhold } 72d561d0adSIngo Weinhold 73d561d0adSIngo Weinhold #else // !TRACE_NETWORK 74d561d0adSIngo Weinhold 75d561d0adSIngo Weinhold #define hex_dump(data, length) 76d561d0adSIngo Weinhold 77d561d0adSIngo Weinhold #endif // !TRACE_NETWORK 78d561d0adSIngo Weinhold 79d561d0adSIngo Weinhold 80e0d09e23SAxel Dörfler // #pragma mark - 81d561d0adSIngo Weinhold 82d561d0adSIngo Weinhold 83d561d0adSIngo Weinhold OFEthernetInterface::OFEthernetInterface() 84e0d09e23SAxel Dörfler : 85e0d09e23SAxel Dörfler EthernetInterface(), 86d561d0adSIngo Weinhold fHandle(OF_FAILED), 87d561d0adSIngo Weinhold fMACAddress(kNoMACAddress) 88d561d0adSIngo Weinhold { 89d561d0adSIngo Weinhold } 90d561d0adSIngo Weinhold 91e0d09e23SAxel Dörfler 92d561d0adSIngo Weinhold OFEthernetInterface::~OFEthernetInterface() 93d561d0adSIngo Weinhold { 94d561d0adSIngo Weinhold if (fHandle != OF_FAILED) 95d561d0adSIngo Weinhold of_close(fHandle); 96d561d0adSIngo Weinhold } 97d561d0adSIngo Weinhold 98e0d09e23SAxel Dörfler 99d561d0adSIngo Weinhold status_t 1007c5a2487SStephan Aßmus OFEthernetInterface::Init(const char *device, const char *parameters) 101d561d0adSIngo Weinhold { 102d561d0adSIngo Weinhold if (!device) 103d561d0adSIngo Weinhold return B_BAD_VALUE; 104d561d0adSIngo Weinhold 105d561d0adSIngo Weinhold // open device 106d561d0adSIngo Weinhold fHandle = of_open(device); 107d561d0adSIngo Weinhold if (fHandle == OF_FAILED) { 108d561d0adSIngo Weinhold printf("opening ethernet device failed\n"); 109d561d0adSIngo Weinhold return B_ERROR; 110d561d0adSIngo Weinhold } 111d561d0adSIngo Weinhold 112*95958839SPulkoMandy intptr_t package = of_instance_to_package(fHandle); 113d561d0adSIngo Weinhold 114d561d0adSIngo Weinhold // get MAC address 115d561d0adSIngo Weinhold int bytesRead = of_getprop(package, "local-mac-address", &fMACAddress, 116d561d0adSIngo Weinhold sizeof(fMACAddress)); 117d561d0adSIngo Weinhold if (bytesRead == OF_FAILED || bytesRead < (int)sizeof(fMACAddress)) { 118d561d0adSIngo Weinhold // Failed to get the MAC address of the network device. The system may 119d561d0adSIngo Weinhold // have a global standard MAC address. 120d561d0adSIngo Weinhold bytesRead = of_getprop(gChosen, "mac-address", &fMACAddress, 121d561d0adSIngo Weinhold sizeof(fMACAddress)); 122d561d0adSIngo Weinhold if (bytesRead == OF_FAILED || bytesRead < (int)sizeof(fMACAddress)) { 123d561d0adSIngo Weinhold printf("Failed to get MAC address\n"); 124d561d0adSIngo Weinhold return B_ERROR; 125d561d0adSIngo Weinhold } 126d561d0adSIngo Weinhold } 127d561d0adSIngo Weinhold 128d561d0adSIngo Weinhold // get IP address 129e0d09e23SAxel Dörfler 130d561d0adSIngo Weinhold // Note: This is a non-standardized way. On my Mac mini the response of the 131e0d09e23SAxel Dörfler // DHCP server is stored as property of /chosen. We try to get it and use 132e0d09e23SAxel Dörfler // the IP address we find in there. 133d561d0adSIngo Weinhold struct { 134d561d0adSIngo Weinhold uint8 irrelevant[16]; 135d561d0adSIngo Weinhold uint32 ip_address; 136d561d0adSIngo Weinhold // ... 137d561d0adSIngo Weinhold } dhcpResponse; 138d561d0adSIngo Weinhold bytesRead = of_getprop(gChosen, "dhcp-response", &dhcpResponse, 139d561d0adSIngo Weinhold sizeof(dhcpResponse)); 140431b9a31SStephan Aßmus if (bytesRead != OF_FAILED && bytesRead == (int)sizeof(dhcpResponse)) { 141d561d0adSIngo Weinhold SetIPAddress(ntohl(dhcpResponse.ip_address)); 142431b9a31SStephan Aßmus } else { 1437c5a2487SStephan Aßmus // try to read manual client IP from boot path 1447c5a2487SStephan Aßmus if (parameters != NULL) { 1457c5a2487SStephan Aßmus char *comma = strrchr(parameters, ','); 1467c5a2487SStephan Aßmus if (comma != NULL && comma != strchr(parameters, ',')) { 14763b69becSAxel Dörfler SetIPAddress(ip_parse_address(comma + 1)); 1487c5a2487SStephan Aßmus } 1497c5a2487SStephan Aßmus } 1507c5a2487SStephan Aßmus if (fIPAddress == 0) { 1517c5a2487SStephan Aßmus // try to read default-client-ip setting 1527c5a2487SStephan Aßmus char defaultClientIP[16]; 153431b9a31SStephan Aßmus package = of_finddevice("/options"); 1547c5a2487SStephan Aßmus bytesRead = of_getprop(package, "default-client-ip", 1557c5a2487SStephan Aßmus defaultClientIP, sizeof(defaultClientIP) - 1); 1567c5a2487SStephan Aßmus if (bytesRead != OF_FAILED && bytesRead > 1) { 1577c5a2487SStephan Aßmus defaultClientIP[bytesRead] = '\0'; 15863b69becSAxel Dörfler ip_addr_t address = ip_parse_address(defaultClientIP); 1597c5a2487SStephan Aßmus SetIPAddress(address); 1607c5a2487SStephan Aßmus } 161431b9a31SStephan Aßmus } 162431b9a31SStephan Aßmus } 163d561d0adSIngo Weinhold 164d561d0adSIngo Weinhold return B_OK; 165d561d0adSIngo Weinhold } 166d561d0adSIngo Weinhold 167e0d09e23SAxel Dörfler 168d561d0adSIngo Weinhold mac_addr_t 169d561d0adSIngo Weinhold OFEthernetInterface::MACAddress() const 170d561d0adSIngo Weinhold { 171d561d0adSIngo Weinhold return fMACAddress; 172d561d0adSIngo Weinhold } 173d561d0adSIngo Weinhold 174e0d09e23SAxel Dörfler 175d561d0adSIngo Weinhold void * 176d561d0adSIngo Weinhold OFEthernetInterface::AllocateSendReceiveBuffer(size_t size) 177d561d0adSIngo Weinhold { 178d561d0adSIngo Weinhold void *dmaMemory; 179d561d0adSIngo Weinhold if (of_call_method(fHandle, "dma-alloc", 1, 1, size, &dmaMemory) 180d561d0adSIngo Weinhold == OF_FAILED) { 181d561d0adSIngo Weinhold return NULL; 182d561d0adSIngo Weinhold } 183d561d0adSIngo Weinhold return dmaMemory; 184d561d0adSIngo Weinhold } 185d561d0adSIngo Weinhold 186e0d09e23SAxel Dörfler 187d561d0adSIngo Weinhold void 188d561d0adSIngo Weinhold OFEthernetInterface::FreeSendReceiveBuffer(void *buffer) 189d561d0adSIngo Weinhold { 190d561d0adSIngo Weinhold if (buffer) 191d561d0adSIngo Weinhold of_call_method(fHandle, "dma-free", 1, 0, buffer); 192d561d0adSIngo Weinhold } 193d561d0adSIngo Weinhold 194e0d09e23SAxel Dörfler 195d561d0adSIngo Weinhold ssize_t 196d561d0adSIngo Weinhold OFEthernetInterface::Send(const void *buffer, size_t size) 197d561d0adSIngo Weinhold { 198d561d0adSIngo Weinhold TRACE(("OFEthernetInterface::Send(%p, %lu)\n", buffer, size)); 199d561d0adSIngo Weinhold 200d561d0adSIngo Weinhold if (!buffer) 201d561d0adSIngo Weinhold return B_BAD_VALUE; 202d561d0adSIngo Weinhold 203d561d0adSIngo Weinhold hex_dump(buffer, size); 204d561d0adSIngo Weinhold 205d561d0adSIngo Weinhold int result = of_write(fHandle, buffer, size); 206d561d0adSIngo Weinhold return (result == OF_FAILED ? B_ERROR : result); 207d561d0adSIngo Weinhold } 208d561d0adSIngo Weinhold 209e0d09e23SAxel Dörfler 210d561d0adSIngo Weinhold ssize_t 211d561d0adSIngo Weinhold OFEthernetInterface::Receive(void *buffer, size_t size) 212d561d0adSIngo Weinhold { 213d561d0adSIngo Weinhold if (!buffer) 214d561d0adSIngo Weinhold return B_BAD_VALUE; 215d561d0adSIngo Weinhold 216d561d0adSIngo Weinhold int result = of_read(fHandle, buffer, size); 217d561d0adSIngo Weinhold 218d561d0adSIngo Weinhold if (result != OF_FAILED && result >= 0) { 219d561d0adSIngo Weinhold TRACE(("OFEthernetInterface::Receive(%p, %lu): received %d bytes\n", 220d561d0adSIngo Weinhold buffer, size, result)); 221d561d0adSIngo Weinhold hex_dump(buffer, result); 222d561d0adSIngo Weinhold } 223d561d0adSIngo Weinhold 224d561d0adSIngo Weinhold return (result == OF_FAILED ? B_ERROR : result); 225d561d0adSIngo Weinhold } 226d561d0adSIngo Weinhold 227d561d0adSIngo Weinhold 228d561d0adSIngo Weinhold // #pragma mark - 229d561d0adSIngo Weinhold 230e0d09e23SAxel Dörfler 231d561d0adSIngo Weinhold status_t 232d561d0adSIngo Weinhold platform_net_stack_init() 233d561d0adSIngo Weinhold { 234d561d0adSIngo Weinhold // Note: At the moment we only do networking at all, if the boot device 235d561d0adSIngo Weinhold // is a network device. If it isn't, we simply fail here. For serious 236d561d0adSIngo Weinhold // support we would want to iterate through the device tree and add all 237d561d0adSIngo Weinhold // network devices. 238d561d0adSIngo Weinhold 239d561d0adSIngo Weinhold // get boot path 240d561d0adSIngo Weinhold char bootPath[192]; 241d561d0adSIngo Weinhold int length = of_getprop(gChosen, "bootpath", bootPath, sizeof(bootPath)); 242d561d0adSIngo Weinhold if (length <= 1) 243d561d0adSIngo Weinhold return B_ERROR; 244d561d0adSIngo Weinhold 245d561d0adSIngo Weinhold // we chop off parameters; otherwise opening the network device might have 246d561d0adSIngo Weinhold // side effects 247d561d0adSIngo Weinhold char *lastComponent = strrchr(bootPath, '/'); 248d561d0adSIngo Weinhold char *parameters = strchr((lastComponent ? lastComponent : bootPath), ':'); 249d561d0adSIngo Weinhold if (parameters) 250d561d0adSIngo Weinhold *parameters = '\0'; 251d561d0adSIngo Weinhold 252d561d0adSIngo Weinhold // get device node 253*95958839SPulkoMandy intptr_t node = of_finddevice(bootPath); 254d561d0adSIngo Weinhold if (node == OF_FAILED) 255d561d0adSIngo Weinhold return B_ERROR; 256d561d0adSIngo Weinhold 257d561d0adSIngo Weinhold // get device type 258d561d0adSIngo Weinhold char type[16]; 259d561d0adSIngo Weinhold if (of_getprop(node, "device_type", type, sizeof(type)) == OF_FAILED 260d561d0adSIngo Weinhold || strcmp("network", type) != 0) { 261d561d0adSIngo Weinhold return B_ERROR; 262d561d0adSIngo Weinhold } 263d561d0adSIngo Weinhold 264d561d0adSIngo Weinhold // create an EthernetInterface object for the device 265d561d0adSIngo Weinhold OFEthernetInterface *interface = new(nothrow) OFEthernetInterface; 266d561d0adSIngo Weinhold if (!interface) 267d561d0adSIngo Weinhold return B_NO_MEMORY; 268d561d0adSIngo Weinhold 2697c5a2487SStephan Aßmus status_t error = interface->Init(bootPath, parameters + 1); 270d561d0adSIngo Weinhold if (error != B_OK) { 271d561d0adSIngo Weinhold delete interface; 272d561d0adSIngo Weinhold return error; 273d561d0adSIngo Weinhold } 274d561d0adSIngo Weinhold 275d561d0adSIngo Weinhold // add it to the net stack 276d561d0adSIngo Weinhold error = NetStack::Default()->AddEthernetInterface(interface); 277d561d0adSIngo Weinhold if (error != B_OK) { 278d561d0adSIngo Weinhold delete interface; 279d561d0adSIngo Weinhold return error; 280d561d0adSIngo Weinhold } 281d561d0adSIngo Weinhold 282d561d0adSIngo Weinhold return B_OK; 283d561d0adSIngo Weinhold } 284