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/IP.h> 7 8 #include <stdio.h> 9 10 #include <boot/net/ARP.h> 11 #include <boot/net/ChainBuffer.h> 12 13 14 //#define TRACE_IP 15 #ifdef TRACE_IP 16 # define TRACE(x) dprintf x 17 #else 18 # define TRACE(x) ; 19 #endif 20 21 22 // #pragma mark - IPSubService 23 24 // constructor 25 IPSubService::IPSubService(const char *serviceName) 26 : NetService(serviceName) 27 { 28 } 29 30 // destructor 31 IPSubService::~IPSubService() 32 { 33 } 34 35 36 // #pragma mark - IPService 37 38 // constructor 39 IPService::IPService(EthernetService *ethernet, ARPService *arpService) 40 : EthernetSubService(kIPServiceName), 41 fEthernet(ethernet), 42 fARPService(arpService) 43 { 44 } 45 46 // destructor 47 IPService::~IPService() 48 { 49 if (fEthernet) 50 fEthernet->UnregisterEthernetSubService(this); 51 } 52 53 // Init 54 status_t 55 IPService::Init() 56 { 57 if (!fEthernet) 58 return B_BAD_VALUE; 59 if (!fEthernet->RegisterEthernetSubService(this)) 60 return B_NO_MEMORY; 61 return B_OK; 62 } 63 64 // IPAddress 65 ip_addr_t 66 IPService::IPAddress() const 67 { 68 return (fEthernet ? fEthernet->IPAddress() : INADDR_ANY); 69 } 70 71 // EthernetProtocol 72 uint16 73 IPService::EthernetProtocol() const 74 { 75 return ETHERTYPE_IP; 76 } 77 78 // HandleEthernetPacket 79 void 80 IPService::HandleEthernetPacket(EthernetService *ethernet, 81 const mac_addr_t &targetAddress, const void *data, size_t size) 82 { 83 TRACE(("IPService::HandleEthernetPacket(): %lu - %lu bytes\n", size, 84 sizeof(ip_header))); 85 86 if (!data || size < sizeof(ip_header)) 87 return; 88 89 // check header 90 const ip_header *header = (const ip_header*)data; 91 // header length OK? 92 int headerLength = header->header_length * 4; 93 if (headerLength < 20 || headerLength > (int)size 94 // IP V4? 95 || header->version != IP_PROTOCOL_VERSION_4 96 // length OK? 97 || ntohs(header->total_length) > size 98 // broadcast or our IP? 99 || (header->destination != htonl(INADDR_BROADCAST) 100 && (fEthernet->IPAddress() == INADDR_ANY 101 || header->destination != htonl(fEthernet->IPAddress()))) 102 // checksum OK? 103 || _Checksum(*header) != 0) { 104 return; 105 } 106 107 // find a service handling this kind of packet 108 int serviceCount = fServices.Count(); 109 for (int i = 0; i < serviceCount; i++) { 110 IPSubService *service = fServices.ElementAt(i); 111 if (service->IPProtocol() == header->protocol) { 112 service->HandleIPPacket(this, ntohl(header->source), 113 ntohl(header->destination), 114 (uint8*)data + headerLength, size - headerLength); 115 break; 116 } 117 } 118 } 119 120 // Send 121 status_t 122 IPService::Send(ip_addr_t destination, uint8 protocol, ChainBuffer *buffer) 123 { 124 TRACE(("IPService::Send(to: %08lx, proto: %lu, %lu bytes)\n", destination, 125 (uint32)protocol, (buffer ? buffer->TotalSize() : 0))); 126 127 if (!buffer) 128 return B_BAD_VALUE; 129 130 if (!fEthernet || !fARPService) 131 return B_NO_INIT; 132 133 // prepare header 134 ip_header header; 135 ChainBuffer headerBuffer(&header, sizeof(header), buffer); 136 header.header_length = 5; // 5 32 bit words, no options 137 header.version = IP_PROTOCOL_VERSION_4; 138 header.type_of_service = 0; 139 header.total_length = htons(headerBuffer.TotalSize()); 140 header.identifier = 0; 141 header.fragment_offset = IP_DONT_FRAGMENT; 142 header.time_to_live = IP_DEFAULT_TIME_TO_LIVE; 143 header.protocol = protocol; 144 header.checksum = 0; 145 header.source = htonl(fEthernet->IPAddress()); 146 header.destination = htonl(destination); 147 148 // compute check sum 149 header.checksum = htons(_Checksum(header)); 150 151 // get target MAC address 152 mac_addr_t targetMAC; 153 status_t error = fARPService->GetMACForIP(destination, targetMAC); 154 if (error != B_OK) 155 return error; 156 157 // send the packet 158 return fEthernet->Send(targetMAC, ETHERTYPE_IP, &headerBuffer); 159 } 160 161 // ProcessIncomingPackets 162 void 163 IPService::ProcessIncomingPackets() 164 { 165 if (fEthernet) 166 fEthernet->ProcessIncomingPackets(); 167 } 168 169 // RegisterIPSubService 170 bool 171 IPService::RegisterIPSubService(IPSubService *service) 172 { 173 return (service && fServices.Add(service) == B_OK); 174 } 175 176 // UnregisterIPSubService 177 bool 178 IPService::UnregisterIPSubService(IPSubService *service) 179 { 180 return (service && fServices.Remove(service) >= 0); 181 } 182 183 // CountSubNetServices 184 int 185 IPService::CountSubNetServices() const 186 { 187 return fServices.Count(); 188 } 189 190 // SubNetServiceAt 191 NetService * 192 IPService::SubNetServiceAt(int index) const 193 { 194 return fServices.ElementAt(index); 195 } 196 197 // _Checksum 198 uint16 199 IPService::_Checksum(const ip_header &header) 200 { 201 ChainBuffer buffer((void*)&header, header.header_length * 4); 202 return ip_checksum(&buffer); 203 } 204 205 206 // #pragma mark - 207 208 // ip_checksum 209 uint16 210 ip_checksum(ChainBuffer *buffer) 211 { 212 // ChainBuffer iterator returning a stream of uint16 (big endian). 213 struct Iterator { 214 Iterator(ChainBuffer *buffer) 215 : fBuffer(buffer), 216 fOffset(-1) 217 { 218 _Next(); 219 } 220 221 bool HasNext() const 222 { 223 return fBuffer; 224 } 225 226 uint16 Next() 227 { 228 uint16 byte = _NextByte(); 229 return (byte << 8) | _NextByte(); 230 } 231 232 private: 233 void _Next() 234 { 235 while (fBuffer) { 236 fOffset++; 237 if (fOffset < (int)fBuffer->Size()) 238 break; 239 240 fOffset = -1; 241 fBuffer = fBuffer->Next(); 242 } 243 } 244 245 uint8 _NextByte() 246 { 247 uint8 byte = (fBuffer ? ((uint8*)fBuffer->Data())[fOffset] : 0); 248 _Next(); 249 return byte; 250 } 251 252 ChainBuffer *fBuffer; 253 int fOffset; 254 }; 255 256 Iterator it(buffer); 257 258 uint32 checksum = 0; 259 while (it.HasNext()) { 260 checksum += it.Next(); 261 while (checksum >> 16) 262 checksum = (checksum & 0xffff) + (checksum >> 16); 263 } 264 265 return ~checksum; 266 } 267