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