xref: /haiku/src/system/boot/platform/openfirmware/network.cpp (revision 957a1b17eb9d13d6dbf164145e82997e16742549)
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