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