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