xref: /haiku/src/system/boot/loader/net/Ethernet.cpp (revision 4e151bc3093293a8ab47aeae854dc80d04e9b41f)
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: %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
174 void
175 EthernetService::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
222 bool
223 EthernetService::RegisterEthernetSubService(EthernetSubService *service)
224 {
225 	return (service && fServices.Add(service) == B_OK);
226 }
227 
228 // UnregisterEthernetSubService
229 bool
230 EthernetService::UnregisterEthernetSubService(EthernetSubService *service)
231 {
232 	return (service && fServices.Remove(service) >= 0);
233 }
234 
235 // CountSubNetServices
236 int
237 EthernetService::CountSubNetServices() const
238 {
239 	return fServices.Count();
240 }
241 
242 // SubNetServiceAt
243 NetService *
244 EthernetService::SubNetServiceAt(int index) const
245 {
246 	return fServices.ElementAt(index);
247 }
248