headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / boot / loader / net / Ethernet.cpp
blobe2724bc89e60ae7faa26ae72b4f046bb4832109b
1 /*
2 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include <boot/net/Ethernet.h>
8 #include <stdio.h>
9 #include <KernelExport.h>
11 #include <boot/net/ChainBuffer.h>
14 //#define TRACE_ETHERNET
15 #ifdef TRACE_ETHERNET
16 # define TRACE(x) dprintf x
17 #else
18 # define TRACE(x) ;
19 #endif
22 // #pragma mark - EthernetInterface
24 // constructor
25 EthernetInterface::EthernetInterface()
26 : fIPAddress(INADDR_ANY)
30 // destructor
31 EthernetInterface::~EthernetInterface()
35 // IPAddress
36 ip_addr_t
37 EthernetInterface::IPAddress() const
39 return fIPAddress;
42 // SetIPAddress
43 void
44 EthernetInterface::SetIPAddress(ip_addr_t ipAddress)
46 fIPAddress = ipAddress;
50 // #pragma mark - EthernetSubService
52 // constructor
53 EthernetSubService::EthernetSubService(const char *serviceName)
54 : NetService(serviceName)
58 // destructor
59 EthernetSubService::~EthernetSubService()
64 // #pragma mark - EthernetService
66 // constructor
67 EthernetService::EthernetService()
68 : NetService(kEthernetServiceName),
69 fInterface(NULL),
70 fSendBuffer(NULL),
71 fReceiveBuffer(NULL)
75 // destructor
76 EthernetService::~EthernetService()
78 if (fSendBuffer)
79 fInterface->FreeSendReceiveBuffer(fSendBuffer);
82 // Init
83 status_t
84 EthernetService::Init(EthernetInterface *interface)
86 if (!interface)
87 return B_BAD_VALUE;
89 fInterface = interface;
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;
97 return B_OK;
100 // MACAddress
101 mac_addr_t
102 EthernetService::MACAddress() const
104 return fInterface->MACAddress();
107 // IPAddress
108 ip_addr_t
109 EthernetService::IPAddress() const
111 return fInterface->IPAddress();
114 // SetIPAddress
115 void
116 EthernetService::SetIPAddress(ip_addr_t ipAddress)
118 fInterface->SetIPAddress(ipAddress);
121 // Send
122 status_t
123 EthernetService::Send(const mac_addr_t &destination, uint16 protocol,
124 ChainBuffer *buffer)
126 TRACE(("EthernetService::Send(to: %012llx, proto: 0x%hx, %lu bytes)\n",
127 destination.ToUInt64(), protocol, (buffer ? buffer->TotalSize() : 0)));
129 if (!fInterface || !fSendBuffer)
130 return B_NO_INIT;
132 // sending has time, but we need to handle incoming packets as soon as
133 // possible
134 ProcessIncomingPackets();
136 if (!buffer)
137 return B_BAD_VALUE;
139 // data too long?
140 size_t dataSize = buffer->TotalSize();
141 if (dataSize > ETHER_MAX_TRANSFER_UNIT)
142 return B_BAD_VALUE;
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);
151 // flatten
152 size_t totalSize = headerBuffer.TotalSize();
153 headerBuffer.Flatten(fSendBuffer);
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;
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;
169 return B_OK;
172 // ProcessIncomingPackets
173 void
174 EthernetService::ProcessIncomingPackets()
176 if (!fInterface || !fReceiveBuffer)
177 return;
179 for (;;) {
180 // read from the interface
181 ssize_t bytesReceived = fInterface->Receive(fReceiveBuffer,
182 RECEIVE_BUFFER_SIZE);
183 if (bytesReceived < 0)
184 return;
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;
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;
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)));
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;
220 // RegisterEthernetSubService
221 bool
222 EthernetService::RegisterEthernetSubService(EthernetSubService *service)
224 return (service && fServices.Add(service) == B_OK);
227 // UnregisterEthernetSubService
228 bool
229 EthernetService::UnregisterEthernetSubService(EthernetSubService *service)
231 return (service && fServices.Remove(service) >= 0);
234 // CountSubNetServices
236 EthernetService::CountSubNetServices() const
238 return fServices.Count();
241 // SubNetServiceAt
242 NetService *
243 EthernetService::SubNetServiceAt(int index) const
245 return fServices.ElementAt(index);