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 <boot/net/Ethernet.h>
7
8#include <stdio.h>
9#include <KernelExport.h>
10
11#include <boot/net/ChainBuffer.h>
12
13
14//#define TRACE_ETHERNET
15#ifdef TRACE_ETHERNET
16#	define TRACE(x) dprintf x
17#else
18#	define TRACE(x) ;
19#endif
20
21
22// #pragma mark - EthernetInterface
23
24// constructor
25EthernetInterface::EthernetInterface()
26	: fIPAddress(INADDR_ANY)
27{
28}
29
30// destructor
31EthernetInterface::~EthernetInterface()
32{
33}
34
35// IPAddress
36ip_addr_t
37EthernetInterface::IPAddress() const
38{
39	return fIPAddress;
40}
41
42// SetIPAddress
43void
44EthernetInterface::SetIPAddress(ip_addr_t ipAddress)
45{
46	fIPAddress = ipAddress;
47}
48
49
50// #pragma mark - EthernetSubService
51
52// constructor
53EthernetSubService::EthernetSubService(const char *serviceName)
54	: NetService(serviceName)
55{
56}
57
58// destructor
59EthernetSubService::~EthernetSubService()
60{
61}
62
63
64// #pragma mark - EthernetService
65
66// constructor
67EthernetService::EthernetService()
68	: NetService(kEthernetServiceName),
69	  fInterface(NULL),
70	  fSendBuffer(NULL),
71	  fReceiveBuffer(NULL)
72{
73}
74
75// destructor
76EthernetService::~EthernetService()
77{
78	if (fSendBuffer)
79		fInterface->FreeSendReceiveBuffer(fSendBuffer);
80
81	delete fInterface;
82}
83
84// Init
85status_t
86EthernetService::Init(EthernetInterface *interface)
87{
88	if (!interface)
89		return B_BAD_VALUE;
90
91	fInterface = interface;
92
93	fSendBuffer = fInterface->AllocateSendReceiveBuffer(
94		SEND_BUFFER_SIZE + RECEIVE_BUFFER_SIZE);
95	if (!fSendBuffer)
96		return B_NO_MEMORY;
97	fReceiveBuffer = (uint8*)fSendBuffer + SEND_BUFFER_SIZE;
98
99	return B_OK;
100}
101
102// MACAddress
103mac_addr_t
104EthernetService::MACAddress() const
105{
106	return fInterface->MACAddress();
107}
108
109// IPAddress
110ip_addr_t
111EthernetService::IPAddress() const
112{
113	return fInterface->IPAddress();
114}
115
116// SetIPAddress
117void
118EthernetService::SetIPAddress(ip_addr_t ipAddress)
119{
120	fInterface->SetIPAddress(ipAddress);
121}
122
123// Send
124status_t
125EthernetService::Send(const mac_addr_t &destination, uint16 protocol,
126	ChainBuffer *buffer)
127{
128	TRACE(("EthernetService::Send(to: %012llx, proto: 0x%hx, %lu bytes)\n",
129		destination.ToUInt64(), protocol, (buffer ? buffer->TotalSize() : 0)));
130
131	if (!fInterface || !fSendBuffer)
132		return B_NO_INIT;
133
134	// sending has time, but we need to handle incoming packets as soon as
135	// possible
136	ProcessIncomingPackets();
137
138	if (!buffer)
139		return B_BAD_VALUE;
140
141	// data too long?
142	size_t dataSize = buffer->TotalSize();
143	if (dataSize > ETHER_MAX_TRANSFER_UNIT)
144		return B_BAD_VALUE;
145
146	// prepend ethernet header
147	ether_header header;
148	ChainBuffer headerBuffer(&header, sizeof(header), buffer);
149	header.source = fInterface->MACAddress();
150	header.destination = destination;
151	header.type = htons(protocol);
152
153	// flatten
154	size_t totalSize = headerBuffer.TotalSize();
155	headerBuffer.Flatten(fSendBuffer);
156
157	// pad data, if necessary
158	if (dataSize < ETHER_MIN_TRANSFER_UNIT) {
159		size_t paddingSize = ETHER_MIN_TRANSFER_UNIT - dataSize;
160		memset((uint8*)fSendBuffer + totalSize, 0, paddingSize);
161		totalSize += paddingSize;
162	}
163
164	// send
165	ssize_t bytesSent = fInterface->Send(fSendBuffer, totalSize);
166	if (bytesSent < 0)
167		return bytesSent;
168	if (bytesSent != (ssize_t)totalSize)
169		return B_ERROR;
170
171	return B_OK;
172}
173
174// ProcessIncomingPackets
175void
176EthernetService::ProcessIncomingPackets()
177{
178	if (!fInterface || !fReceiveBuffer)
179		return;
180
181	for (;;) {
182		// read from the interface
183		ssize_t bytesReceived = fInterface->Receive(fReceiveBuffer,
184			RECEIVE_BUFFER_SIZE);
185		if (bytesReceived < 0)
186			return;
187
188		// basic sanity checks (packet too small/too big)
189		if (bytesReceived
190				< (ssize_t)sizeof(ether_header) + ETHER_MIN_TRANSFER_UNIT
191			|| bytesReceived
192				> (ssize_t)sizeof(ether_header) + ETHER_MAX_TRANSFER_UNIT) {
193			continue;
194		}
195
196		// is the packet intended for us?
197		ether_header *header = (ether_header*)fReceiveBuffer;
198		if (header->destination != kBroadcastMACAddress
199			&& header->destination != fInterface->MACAddress()) {
200			continue;
201		}
202
203		TRACE(("EthernetService::ProcessIncomingPackets(): received ethernet "
204			"frame: to: %012llx, proto: 0x%hx, %ld bytes\n",
205			header->destination.ToUInt64(), ntohs(header->type),
206			bytesReceived - (ssize_t)sizeof(ether_header)));
207
208		// find a service handling this kind of packet
209		int serviceCount = fServices.Count();
210		for (int i = 0; i < serviceCount; i++) {
211			EthernetSubService *service = fServices.ElementAt(i);
212			if (service->EthernetProtocol() == ntohs(header->type)) {
213				service->HandleEthernetPacket(this, header->destination,
214					(uint8*)fReceiveBuffer + sizeof(ether_header),
215					bytesReceived - sizeof(ether_header));
216				break;
217			}
218		}
219	}
220}
221
222// RegisterEthernetSubService
223bool
224EthernetService::RegisterEthernetSubService(EthernetSubService *service)
225{
226	return (service && fServices.Add(service) == B_OK);
227}
228
229// UnregisterEthernetSubService
230bool
231EthernetService::UnregisterEthernetSubService(EthernetSubService *service)
232{
233	return (service && fServices.Remove(service) >= 0);
234}
235
236// CountSubNetServices
237int
238EthernetService::CountSubNetServices() const
239{
240	return fServices.Count();
241}
242
243// SubNetServiceAt
244NetService *
245EthernetService::SubNetServiceAt(int index) const
246{
247	return fServices.ElementAt(index);
248}
249