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 delete fInterface; 82} 83 84// Init 85status_t 86EthernetService::Init(EthernetInterface *interface) 87{ 88 if (!interface) 89 return B_BAD_VALUE; 90 91 fInterface = interface; 92 93 fSendBuffer = fInterface->AllocateSendReceiveBuffer( 94 SEND_BUFFER_SIZE + RECEIVE_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 103mac_addr_t 104EthernetService::MACAddress() const 105{ 106 return fInterface->MACAddress(); 107} 108 109// IPAddress 110ip_addr_t 111EthernetService::IPAddress() const 112{ 113 return fInterface->IPAddress(); 114} 115 116// SetIPAddress 117void 118EthernetService::SetIPAddress(ip_addr_t ipAddress) 119{ 120 fInterface->SetIPAddress(ipAddress); 121} 122 123// Send 124status_t 125EthernetService::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 175void 176EthernetService::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 223bool 224EthernetService::RegisterEthernetSubService(EthernetSubService *service) 225{ 226 return (service && fServices.Add(service) == B_OK); 227} 228 229// UnregisterEthernetSubService 230bool 231EthernetService::UnregisterEthernetSubService(EthernetSubService *service) 232{ 233 return (service && fServices.Remove(service) >= 0); 234} 235 236// CountSubNetServices 237int 238EthernetService::CountSubNetServices() const 239{ 240 return fServices.Count(); 241} 242 243// SubNetServiceAt 244NetService * 245EthernetService::SubNetServiceAt(int index) const 246{ 247 return fServices.ElementAt(index); 248} 249