vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / network / protocols / icmp6 / icmp6.cpp
blob4f2dd1d30838d9d2b47dcf40ec2c9bf9d1d48371
1 /*
2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <net_datalink.h>
8 #include <net_protocol.h>
9 #include <net_stack.h>
10 #include <net_datalink_protocol.h>
11 #include <NetUtilities.h>
12 #include <NetBufferUtilities.h>
14 #include <KernelExport.h>
15 #include <util/list.h>
17 #include <netinet/icmp6.h>
18 #include <netinet/in.h>
19 #include <new>
20 #include <stdlib.h>
21 #include <string.h>
23 #include <ipv6_datagram/ndp.h>
26 #define TRACE_ICMP6
27 #ifdef TRACE_ICMP6
28 # define TRACE(x) dprintf x
29 #else
30 # define TRACE(x) ;
31 #endif
34 typedef NetBufferField<uint16, offsetof(icmp6_hdr, icmp6_cksum)> ICMP6ChecksumField;
37 net_buffer_module_info *gBufferModule;
38 static net_stack_module_info *sStackModule;
39 static net_ndp_module_info *sIPv6NDPModule;
42 net_protocol *
43 icmp6_init_protocol(net_socket *socket)
45 net_protocol *protocol = new (std::nothrow) net_protocol;
46 if (protocol == NULL)
47 return NULL;
49 return protocol;
53 status_t
54 icmp6_uninit_protocol(net_protocol *protocol)
56 delete protocol;
57 return B_OK;
61 status_t
62 icmp6_open(net_protocol *protocol)
64 return B_OK;
68 status_t
69 icmp6_close(net_protocol *protocol)
71 return B_OK;
75 status_t
76 icmp6_free(net_protocol *protocol)
78 return B_OK;
82 status_t
83 icmp6_connect(net_protocol *protocol, const struct sockaddr *address)
85 return B_ERROR;
89 status_t
90 icmp6_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
92 return EOPNOTSUPP;
96 status_t
97 icmp6_control(net_protocol *protocol, int level, int option, void *value,
98 size_t *_length)
100 return protocol->next->module->control(protocol->next, level, option,
101 value, _length);
105 status_t
106 icmp6_getsockopt(net_protocol *protocol, int level, int option,
107 void *value, int *length)
109 return protocol->next->module->getsockopt(protocol->next, level, option,
110 value, length);
114 status_t
115 icmp6_setsockopt(net_protocol *protocol, int level, int option,
116 const void *value, int length)
118 return protocol->next->module->setsockopt(protocol->next, level, option,
119 value, length);
123 status_t
124 icmp6_bind(net_protocol *protocol, const struct sockaddr *address)
126 return B_ERROR;
130 status_t
131 icmp6_unbind(net_protocol *protocol, struct sockaddr *address)
133 return B_ERROR;
137 status_t
138 icmp6_listen(net_protocol *protocol, int count)
140 return EOPNOTSUPP;
144 status_t
145 icmp6_shutdown(net_protocol *protocol, int direction)
147 return EOPNOTSUPP;
151 status_t
152 icmp6_send_data(net_protocol *protocol, net_buffer *buffer)
154 return protocol->next->module->send_data(protocol->next, buffer);
158 status_t
159 icmp6_send_routed_data(net_protocol *protocol, struct net_route *route,
160 net_buffer *buffer)
162 return protocol->next->module->send_routed_data(protocol->next, route, buffer);
166 ssize_t
167 icmp6_send_avail(net_protocol *protocol)
169 return B_ERROR;
173 status_t
174 icmp6_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
175 net_buffer **_buffer)
177 return B_ERROR;
181 ssize_t
182 icmp6_read_avail(net_protocol *protocol)
184 return B_ERROR;
188 struct net_domain *
189 icmp6_get_domain(net_protocol *protocol)
191 return protocol->next->module->get_domain(protocol->next);
195 size_t
196 icmp6_get_mtu(net_protocol *protocol, const struct sockaddr *address)
198 return protocol->next->module->get_mtu(protocol->next, address);
202 static net_domain*
203 get_domain(struct net_buffer* buffer)
205 net_domain* domain;
206 if (buffer->interface_address != NULL)
207 domain = buffer->interface_address->domain;
208 else
209 domain = sStackModule->get_domain(buffer->source->sa_family);
211 if (domain == NULL || domain->module == NULL)
212 return NULL;
214 return domain;
218 status_t
219 icmp6_receive_data(net_buffer *buffer)
221 TRACE(("ICMPv6 received some data, buffer length %" B_PRIu32 "\n",
222 buffer->size));
224 net_domain* domain = get_domain(buffer);
225 if (domain == NULL)
226 return B_ERROR;
228 NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
229 if (bufferHeader.Status() < B_OK)
230 return bufferHeader.Status();
232 icmp6_hdr &header = bufferHeader.Data();
234 TRACE((" got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
235 header.icmp6_code, header.icmp6_cksum));
237 net_address_module_info* addressModule = domain->address_module;
239 // compute and check the checksum
240 if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
241 IPPROTO_ICMPV6) != 0)
242 return B_BAD_DATA;
244 switch (header.icmp6_type) {
245 case ICMP6_ECHO_REPLY:
246 break;
248 case ICMP6_ECHO_REQUEST:
250 if (buffer->interface_address != NULL) {
251 // We only reply to echo requests of our local interface; we
252 // don't reply to broadcast requests
253 if (!domain->address_module->equal_addresses(
254 buffer->interface_address->local, buffer->destination))
255 break;
258 net_buffer *reply = gBufferModule->duplicate(buffer);
259 if (reply == NULL)
260 return B_NO_MEMORY;
262 gBufferModule->swap_addresses(reply);
264 // There already is an ICMP header, and we'll reuse it
265 NetBufferHeaderReader<icmp6_hdr> header(reply);
267 header->icmp6_type = ICMP6_ECHO_REPLY;
268 header->icmp6_code = 0;
269 header->icmp6_cksum = 0;
271 header.Sync();
273 *ICMP6ChecksumField(reply) = Checksum::PseudoHeader(addressModule,
274 gBufferModule, buffer, IPPROTO_ICMPV6);
276 status_t status = domain->module->send_data(NULL, reply);
277 if (status < B_OK) {
278 gBufferModule->free(reply);
279 return status;
283 default:
284 // unrecognized messages go to neighbor discovery protocol handler
285 return sIPv6NDPModule->receive_data(buffer);
288 gBufferModule->free(buffer);
289 return B_OK;
293 status_t
294 icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
296 // TODO: does this look OK?
297 return icmp6_receive_data(buffer);
301 status_t
302 icmp6_error_received(net_error code, net_buffer* data)
304 return B_ERROR;
308 status_t
309 icmp6_error_reply(net_protocol* protocol, net_buffer* buffer, net_error error,
310 net_error_data* errorData)
312 return B_ERROR;
316 // #pragma mark -
319 static status_t
320 icmp6_init()
322 sStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6,
323 "network/protocols/icmp6/v1",
324 "network/protocols/ipv6/v1",
325 NULL);
327 sStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_ICMPV6,
328 "network/protocols/icmp6/v1");
330 return B_OK;
334 static status_t
335 icmp6_std_ops(int32 op, ...)
337 switch (op) {
338 case B_MODULE_INIT:
339 return icmp6_init();
341 case B_MODULE_UNINIT:
342 return B_OK;
344 default:
345 return B_ERROR;
350 net_protocol_module_info sICMP6Module = {
352 "network/protocols/icmp6/v1",
354 icmp6_std_ops
356 NET_PROTOCOL_ATOMIC_MESSAGES,
358 icmp6_init_protocol,
359 icmp6_uninit_protocol,
360 icmp6_open,
361 icmp6_close,
362 icmp6_free,
363 icmp6_connect,
364 icmp6_accept,
365 icmp6_control,
366 icmp6_getsockopt,
367 icmp6_setsockopt,
368 icmp6_bind,
369 icmp6_unbind,
370 icmp6_listen,
371 icmp6_shutdown,
372 icmp6_send_data,
373 icmp6_send_routed_data,
374 icmp6_send_avail,
375 icmp6_read_data,
376 icmp6_read_avail,
377 icmp6_get_domain,
378 icmp6_get_mtu,
379 icmp6_receive_data,
380 icmp6_deliver_data,
381 icmp6_error_received,
382 icmp6_error_reply,
383 NULL, // add_ancillary_data()
384 NULL, // process_ancillary_data()
385 NULL, // process_ancillary_data_no_container()
386 NULL, // send_data_no_buffer()
387 NULL // read_data_no_buffer()
390 module_dependency module_dependencies[] = {
391 {NET_STACK_MODULE_NAME, (module_info **)&sStackModule},
392 {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
393 {"network/datalink_protocols/ipv6_datagram/ndp/v1",
394 (module_info **)&sIPv6NDPModule},
398 module_info *modules[] = {
399 (module_info *)&sICMP6Module,
400 NULL