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
82// Init
83status_t
84EthernetService::Init(EthernetInterface *interface)
85{
86	if (!interface)
87		return B_BAD_VALUE;
88
89	fInterface = interface;
90
91	fSendBuffer = fInterface->AllocateSendReceiveBuffer(
92		SEND_BUFFER_SIZE + RECEIVE_BUFFER_SIZE);
93	if (!fSendBuffer)
94		return B_NO_MEMORY;
95	fReceiveBuffer = (uint8*)fSendBuffer + SEND_BUFFER_SIZE;
96
97	return B_OK;
98}
99
100// MACAddress
101mac_addr_t
102EthernetService::MACAddress() const
103{
104	return fInterface->MACAddress();
105}
106
107// IPAddress
108ip_addr_t
109EthernetService::IPAddress() const
110{
111	return fInterface->IPAddress();
112}
113
114// SetIPAddress
115void
116EthernetService::SetIPAddress(ip_addr_t ipAddress)
117{
118	fInterface->SetIPAddress(ipAddress);
119}
120
121// Send
122status_t
123EthernetService::Send(const mac_addr_t &destination, uint16 protocol,
124	ChainBuffer *buffer)
125{
126	TRACE(("EthernetService::Send(to: %012" B_PRIx64 ", proto: 0x%hx, %"
127		PRIu32 " bytes)\n",
128		destination.ToUInt64(), protocol, (buffer ? buffer->TotalSize() : 0)));
129
130	if (!fInterface || !fSendBuffer)
131		return B_NO_INIT;
132
133	// sending has time, but we need to handle incoming packets as soon as
134	// possible
135	ProcessIncomingPackets();
136
137	if (!buffer)
138		return B_BAD_VALUE;
139
140	// data too long?
141	size_t dataSize = buffer->TotalSize();
142	if (dataSize > ETHER_MAX_TRANSFER_UNIT)
143		return B_BAD_VALUE;
144
145	// prepend ethernet header
146	ether_header header;
147	ChainBuffer headerBuffer(&header, sizeof(header), buffer);
148	header.source = fInterface->MACAddress();
149	header.destination = destination;
150	header.type = htons(protocol);
151
152	// flatten
153	size_t totalSize = headerBuffer.TotalSize();
154	headerBuffer.Flatten(fSendBuffer);
155
156	// pad data, if necessary
157	if (dataSize < ETHER_MIN_TRANSFER_UNIT) {
158		size_t paddingSize = ETHER_MIN_TRANSFER_UNIT - dataSize;
159		memset((uint8*)fSendBuffer + totalSize, 0, paddingSize);
160		totalSize += paddingSize;
161	}
162
163	// send
164	ssize_t bytesSent = fInterface->Send(fSendBuffer, totalSize);
165	if (bytesSent < 0)
166		return bytesSent;
167	if (bytesSent != (ssize_t)totalSize)
168		return B_ERROR;
169
170	return B_OK;
171}
172
173// ProcessIncomingPackets
174void
175EthernetService::ProcessIncomingPackets()
176{
177	if (!fInterface || !fReceiveBuffer)
178		return;
179
180	for (;;) {
181		// read from the interface
182		ssize_t bytesReceived = fInterface->Receive(fReceiveBuffer,
183			RECEIVE_BUFFER_SIZE);
184		if (bytesReceived < 0)
185			return;
186
187		// basic sanity checks (packet too small/too big)
188		if (bytesReceived
189				< (ssize_t)sizeof(ether_header) + ETHER_MIN_TRANSFER_UNIT
190			|| bytesReceived
191				> (ssize_t)sizeof(ether_header) + ETHER_MAX_TRANSFER_UNIT) {
192			continue;
193		}
194
195		// is the packet intended for us?
196		ether_header *header = (ether_header*)fReceiveBuffer;
197		if (header->destination != kBroadcastMACAddress
198			&& header->destination != fInterface->MACAddress()) {
199			continue;
200		}
201
202		TRACE(("EthernetService::ProcessIncomingPackets(): received ethernet "
203			"frame: to: %012" B_PRIx64 ", proto: 0x%hx, %" B_PRIuSIZE " bytes\n",
204			header->destination.ToUInt64(), ntohs(header->type),
205			bytesReceived - (ssize_t)sizeof(ether_header)));
206
207		// find a service handling this kind of packet
208		int serviceCount = fServices.Count();
209		for (int i = 0; i < serviceCount; i++) {
210			EthernetSubService *service = fServices.ElementAt(i);
211			if (service->EthernetProtocol() == ntohs(header->type)) {
212				service->HandleEthernetPacket(this, header->destination,
213					(uint8*)fReceiveBuffer + sizeof(ether_header),
214					bytesReceived - sizeof(ether_header));
215				break;
216			}
217		}
218	}
219}
220
221// RegisterEthernetSubService
222bool
223EthernetService::RegisterEthernetSubService(EthernetSubService *service)
224{
225	return (service && fServices.Add(service) == B_OK);
226}
227
228// UnregisterEthernetSubService
229bool
230EthernetService::UnregisterEthernetSubService(EthernetSubService *service)
231{
232	return (service && fServices.Remove(service) >= 0);
233}
234
235// CountSubNetServices
236int
237EthernetService::CountSubNetServices() const
238{
239	return fServices.Count();
240}
241
242// SubNetServiceAt
243NetService *
244EthernetService::SubNetServiceAt(int index) const
245{
246	return fServices.ElementAt(index);
247}
248