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 82// Init 83status_t 84EthernetService::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 101mac_addr_t 102EthernetService::MACAddress() const 103{ 104 return fInterface->MACAddress(); 105} 106 107// IPAddress 108ip_addr_t 109EthernetService::IPAddress() const 110{ 111 return fInterface->IPAddress(); 112} 113 114// SetIPAddress 115void 116EthernetService::SetIPAddress(ip_addr_t ipAddress) 117{ 118 fInterface->SetIPAddress(ipAddress); 119} 120 121// Send 122status_t 123EthernetService::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 174void 175EthernetService::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 222bool 223EthernetService::RegisterEthernetSubService(EthernetSubService *service) 224{ 225 return (service && fServices.Add(service) == B_OK); 226} 227 228// UnregisterEthernetSubService 229bool 230EthernetService::UnregisterEthernetSubService(EthernetSubService *service) 231{ 232 return (service && fServices.Remove(service) >= 0); 233} 234 235// CountSubNetServices 236int 237EthernetService::CountSubNetServices() const 238{ 239 return fServices.Count(); 240} 241 242// SubNetServiceAt 243NetService * 244EthernetService::SubNetServiceAt(int index) const 245{ 246 return fServices.ElementAt(index); 247} 248