xref: /haiku/src/system/boot/loader/net/IP.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
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