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
IPSubService(const char * serviceName)26 IPSubService::IPSubService(const char *serviceName)
27 : NetService(serviceName)
28 {
29 }
30
31 // destructor
~IPSubService()32 IPSubService::~IPSubService()
33 {
34 }
35
36
37 // #pragma mark - IPService
38
39 // constructor
IPService(EthernetService * ethernet,ARPService * arpService)40 IPService::IPService(EthernetService *ethernet, ARPService *arpService)
41 : EthernetSubService(kIPServiceName),
42 fEthernet(ethernet),
43 fARPService(arpService)
44 {
45 }
46
47 // destructor
~IPService()48 IPService::~IPService()
49 {
50 if (fEthernet)
51 fEthernet->UnregisterEthernetSubService(this);
52 }
53
54 // Init
55 status_t
Init()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
IPAddress() const67 IPService::IPAddress() const
68 {
69 return (fEthernet ? fEthernet->IPAddress() : INADDR_ANY);
70 }
71
72 // EthernetProtocol
73 uint16
EthernetProtocol() const74 IPService::EthernetProtocol() const
75 {
76 return ETHERTYPE_IP;
77 }
78
79 // HandleEthernetPacket
80 void
HandleEthernetPacket(EthernetService * ethernet,const mac_addr_t & targetAddress,const void * data,size_t size)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,
116 ntohs(header->total_length) - headerLength);
117 break;
118 }
119 }
120 }
121
122 // Send
123 status_t
Send(ip_addr_t destination,uint8 protocol,ChainBuffer * buffer)124 IPService::Send(ip_addr_t destination, uint8 protocol, ChainBuffer *buffer)
125 {
126 TRACE(("IPService::Send(to: %08lx, proto: %lu, %lu bytes)\n", destination,
127 (uint32)protocol, (buffer ? buffer->TotalSize() : 0)));
128
129 if (!buffer)
130 return B_BAD_VALUE;
131
132 if (!fEthernet || !fARPService)
133 return B_NO_INIT;
134
135 // prepare header
136 ip_header header;
137 ChainBuffer headerBuffer(&header, sizeof(header), buffer);
138 header.header_length = 5; // 5 32 bit words, no options
139 header.version = IP_PROTOCOL_VERSION_4;
140 header.type_of_service = 0;
141 header.total_length = htons(headerBuffer.TotalSize());
142 header.identifier = 0;
143 header.fragment_offset = htons(IP_DONT_FRAGMENT);
144 header.time_to_live = IP_DEFAULT_TIME_TO_LIVE;
145 header.protocol = protocol;
146 header.checksum = 0;
147 header.source = htonl(fEthernet->IPAddress());
148 header.destination = htonl(destination);
149
150 // compute check sum
151 header.checksum = htons(_Checksum(header));
152
153 // get target MAC address
154 mac_addr_t targetMAC;
155 status_t error = fARPService->GetMACForIP(destination, targetMAC);
156 if (error != B_OK)
157 return error;
158
159 // send the packet
160 return fEthernet->Send(targetMAC, ETHERTYPE_IP, &headerBuffer);
161 }
162
163 // ProcessIncomingPackets
164 void
ProcessIncomingPackets()165 IPService::ProcessIncomingPackets()
166 {
167 if (fEthernet)
168 fEthernet->ProcessIncomingPackets();
169 }
170
171 // RegisterIPSubService
172 bool
RegisterIPSubService(IPSubService * service)173 IPService::RegisterIPSubService(IPSubService *service)
174 {
175 return (service && fServices.Add(service) == B_OK);
176 }
177
178 // UnregisterIPSubService
179 bool
UnregisterIPSubService(IPSubService * service)180 IPService::UnregisterIPSubService(IPSubService *service)
181 {
182 return (service && fServices.Remove(service) >= 0);
183 }
184
185 // CountSubNetServices
186 int
CountSubNetServices() const187 IPService::CountSubNetServices() const
188 {
189 return fServices.Count();
190 }
191
192 // SubNetServiceAt
193 NetService *
SubNetServiceAt(int index) const194 IPService::SubNetServiceAt(int index) const
195 {
196 return fServices.ElementAt(index);
197 }
198
199 // _Checksum
200 uint16
_Checksum(const ip_header & header)201 IPService::_Checksum(const ip_header &header)
202 {
203 ChainBuffer buffer((void*)&header, header.header_length * 4);
204 return ip_checksum(&buffer);
205 }
206
207
208 // #pragma mark -
209
210 // ip_checksum
211 uint16
ip_checksum(ChainBuffer * buffer)212 ip_checksum(ChainBuffer *buffer)
213 {
214 // ChainBuffer iterator returning a stream of uint16 (big endian).
215 struct Iterator {
216 Iterator(ChainBuffer *buffer)
217 : fBuffer(buffer),
218 fOffset(-1)
219 {
220 _Next();
221 }
222
223 bool HasNext() const
224 {
225 return fBuffer;
226 }
227
228 uint16 Next()
229 {
230 uint16 byte = _NextByte();
231 return (byte << 8) | _NextByte();
232 }
233
234 private:
235 void _Next()
236 {
237 while (fBuffer) {
238 fOffset++;
239 if (fOffset < (int)fBuffer->Size())
240 break;
241
242 fOffset = -1;
243 fBuffer = fBuffer->Next();
244 }
245 }
246
247 uint8 _NextByte()
248 {
249 uint8 byte = (fBuffer ? ((uint8*)fBuffer->Data())[fOffset] : 0);
250 _Next();
251 return byte;
252 }
253
254 ChainBuffer *fBuffer;
255 int fOffset;
256 };
257
258 Iterator it(buffer);
259
260 uint32 checksum = 0;
261 while (it.HasNext()) {
262 checksum += it.Next();
263 while (checksum >> 16)
264 checksum = (checksum & 0xffff) + (checksum >> 16);
265 }
266
267 return ~checksum;
268 }
269
270
271 ip_addr_t
ip_parse_address(const char * string)272 ip_parse_address(const char *string)
273 {
274 ip_addr_t address = 0;
275 int components = 0;
276
277 // TODO: Handles only IPv4 addresses for now.
278 while (components < 4) {
279 address |= strtol(string, NULL, 0) << ((4 - components - 1) * 8);
280
281 const char *dot = strchr(string, '.');
282 if (dot == NULL)
283 break;
284
285 string = dot + 1;
286 components++;
287 }
288
289 return address;
290 }
291