xref: /haiku/src/system/boot/loader/net/Ethernet.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
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
25 EthernetInterface::EthernetInterface()
26 	: fIPAddress(INADDR_ANY)
27 {
28 }
29 
30 // destructor
31 EthernetInterface::~EthernetInterface()
32 {
33 }
34 
35 // IPAddress
36 ip_addr_t
37 EthernetInterface::IPAddress() const
38 {
39 	return fIPAddress;
40 }
41 
42 // SetIPAddress
43 void
44 EthernetInterface::SetIPAddress(ip_addr_t ipAddress)
45 {
46 	fIPAddress = ipAddress;
47 }
48 
49 
50 // #pragma mark - EthernetSubService
51 
52 // constructor
53 EthernetSubService::EthernetSubService(const char *serviceName)
54 	: NetService(serviceName)
55 {
56 }
57 
58 // destructor
59 EthernetSubService::~EthernetSubService()
60 {
61 }
62 
63 
64 // #pragma mark - EthernetService
65 
66 // constructor
67 EthernetService::EthernetService()
68 	: NetService(kEthernetServiceName),
69 	  fInterface(NULL),
70 	  fSendBuffer(NULL),
71 	  fReceiveBuffer(NULL)
72 {
73 }
74 
75 // destructor
76 EthernetService::~EthernetService()
77 {
78 	if (fSendBuffer)
79 		fInterface->FreeSendReceiveBuffer(fSendBuffer);
80 
81 	delete fInterface;
82 }
83 
84 // Init
85 status_t
86 EthernetService::Init(EthernetInterface *interface)
87 {
88 	if (!interface)
89 		return B_BAD_VALUE;
90 
91 	fInterface = interface;
92 
93 	fSendBuffer = fInterface->AllocateSendReceiveBuffer(
94 		2 * SEND_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
103 mac_addr_t
104 EthernetService::MACAddress() const
105 {
106 	return fInterface->MACAddress();
107 }
108 
109 // IPAddress
110 ip_addr_t
111 EthernetService::IPAddress() const
112 {
113 	return fInterface->IPAddress();
114 }
115 
116 // SetIPAddress
117 void
118 EthernetService::SetIPAddress(ip_addr_t ipAddress)
119 {
120 	fInterface->SetIPAddress(ipAddress);
121 }
122 
123 // Send
124 status_t
125 EthernetService::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
175 void
176 EthernetService::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
223 bool
224 EthernetService::RegisterEthernetSubService(EthernetSubService *service)
225 {
226 	return (service && fServices.Add(service) == B_OK);
227 }
228 
229 // UnregisterEthernetSubService
230 bool
231 EthernetService::UnregisterEthernetSubService(EthernetSubService *service)
232 {
233 	return (service && fServices.Remove(service) >= 0);
234 }
235 
236 // CountSubNetServices
237 int
238 EthernetService::CountSubNetServices() const
239 {
240 	return fServices.Count();
241 }
242 
243 // SubNetServiceAt
244 NetService *
245 EthernetService::SubNetServiceAt(int index) const
246 {
247 	return fServices.ElementAt(index);
248 }
249