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