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