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