1 /*
2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
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>
13
14 #include <KernelExport.h>
15 #include <util/list.h>
16
17 #include <netinet/icmp6.h>
18 #include <netinet/in.h>
19 #include <new>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <ipv6_datagram/ndp.h>
24
25
26 //#define TRACE_ICMP6
27 #ifdef TRACE_ICMP6
28 # define TRACE(x) dprintf x
29 #else
30 # define TRACE(x) ;
31 #endif
32
33
34 typedef NetBufferField<uint16, offsetof(icmp6_hdr, icmp6_cksum)> ICMP6ChecksumField;
35
36
37 net_buffer_module_info *gBufferModule;
38 static net_stack_module_info *sStackModule;
39 static net_ndp_module_info *sIPv6NDPModule;
40
41
42 net_protocol *
icmp6_init_protocol(net_socket * socket)43 icmp6_init_protocol(net_socket *socket)
44 {
45 net_protocol *protocol = new (std::nothrow) net_protocol;
46 if (protocol == NULL)
47 return NULL;
48
49 return protocol;
50 }
51
52
53 status_t
icmp6_uninit_protocol(net_protocol * protocol)54 icmp6_uninit_protocol(net_protocol *protocol)
55 {
56 delete protocol;
57 return B_OK;
58 }
59
60
61 status_t
icmp6_open(net_protocol * protocol)62 icmp6_open(net_protocol *protocol)
63 {
64 return B_OK;
65 }
66
67
68 status_t
icmp6_close(net_protocol * protocol)69 icmp6_close(net_protocol *protocol)
70 {
71 return B_OK;
72 }
73
74
75 status_t
icmp6_free(net_protocol * protocol)76 icmp6_free(net_protocol *protocol)
77 {
78 return B_OK;
79 }
80
81
82 status_t
icmp6_connect(net_protocol * protocol,const struct sockaddr * address)83 icmp6_connect(net_protocol *protocol, const struct sockaddr *address)
84 {
85 return B_ERROR;
86 }
87
88
89 status_t
icmp6_accept(net_protocol * protocol,struct net_socket ** _acceptedSocket)90 icmp6_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
91 {
92 return EOPNOTSUPP;
93 }
94
95
96 status_t
icmp6_control(net_protocol * protocol,int level,int option,void * value,size_t * _length)97 icmp6_control(net_protocol *protocol, int level, int option, void *value,
98 size_t *_length)
99 {
100 return protocol->next->module->control(protocol->next, level, option,
101 value, _length);
102 }
103
104
105 status_t
icmp6_getsockopt(net_protocol * protocol,int level,int option,void * value,int * length)106 icmp6_getsockopt(net_protocol *protocol, int level, int option,
107 void *value, int *length)
108 {
109 return protocol->next->module->getsockopt(protocol->next, level, option,
110 value, length);
111 }
112
113
114 status_t
icmp6_setsockopt(net_protocol * protocol,int level,int option,const void * value,int length)115 icmp6_setsockopt(net_protocol *protocol, int level, int option,
116 const void *value, int length)
117 {
118 return protocol->next->module->setsockopt(protocol->next, level, option,
119 value, length);
120 }
121
122
123 status_t
icmp6_bind(net_protocol * protocol,const struct sockaddr * address)124 icmp6_bind(net_protocol *protocol, const struct sockaddr *address)
125 {
126 return B_ERROR;
127 }
128
129
130 status_t
icmp6_unbind(net_protocol * protocol,struct sockaddr * address)131 icmp6_unbind(net_protocol *protocol, struct sockaddr *address)
132 {
133 return B_ERROR;
134 }
135
136
137 status_t
icmp6_listen(net_protocol * protocol,int count)138 icmp6_listen(net_protocol *protocol, int count)
139 {
140 return EOPNOTSUPP;
141 }
142
143
144 status_t
icmp6_shutdown(net_protocol * protocol,int direction)145 icmp6_shutdown(net_protocol *protocol, int direction)
146 {
147 return EOPNOTSUPP;
148 }
149
150
151 status_t
icmp6_send_data(net_protocol * protocol,net_buffer * buffer)152 icmp6_send_data(net_protocol *protocol, net_buffer *buffer)
153 {
154 return protocol->next->module->send_data(protocol->next, buffer);
155 }
156
157
158 status_t
icmp6_send_routed_data(net_protocol * protocol,struct net_route * route,net_buffer * buffer)159 icmp6_send_routed_data(net_protocol *protocol, struct net_route *route,
160 net_buffer *buffer)
161 {
162 return protocol->next->module->send_routed_data(protocol->next, route, buffer);
163 }
164
165
166 ssize_t
icmp6_send_avail(net_protocol * protocol)167 icmp6_send_avail(net_protocol *protocol)
168 {
169 return B_ERROR;
170 }
171
172
173 status_t
icmp6_read_data(net_protocol * protocol,size_t numBytes,uint32 flags,net_buffer ** _buffer)174 icmp6_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
175 net_buffer **_buffer)
176 {
177 return B_ERROR;
178 }
179
180
181 ssize_t
icmp6_read_avail(net_protocol * protocol)182 icmp6_read_avail(net_protocol *protocol)
183 {
184 return B_ERROR;
185 }
186
187
188 struct net_domain *
icmp6_get_domain(net_protocol * protocol)189 icmp6_get_domain(net_protocol *protocol)
190 {
191 return protocol->next->module->get_domain(protocol->next);
192 }
193
194
195 size_t
icmp6_get_mtu(net_protocol * protocol,const struct sockaddr * address)196 icmp6_get_mtu(net_protocol *protocol, const struct sockaddr *address)
197 {
198 return protocol->next->module->get_mtu(protocol->next, address);
199 }
200
201
202 static net_domain*
get_domain(struct net_buffer * buffer)203 get_domain(struct net_buffer* buffer)
204 {
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);
210
211 if (domain == NULL || domain->module == NULL)
212 return NULL;
213
214 return domain;
215 }
216
217
218 status_t
icmp6_receive_data(net_buffer * buffer)219 icmp6_receive_data(net_buffer *buffer)
220 {
221 TRACE(("ICMPv6 received some data, buffer length %" B_PRIu32 "\n",
222 buffer->size));
223
224 net_domain* domain = get_domain(buffer);
225 if (domain == NULL)
226 return B_ERROR;
227
228 NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
229 if (bufferHeader.Status() < B_OK)
230 return bufferHeader.Status();
231
232 icmp6_hdr &header = bufferHeader.Data();
233
234 TRACE((" got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
235 header.icmp6_code, header.icmp6_cksum));
236
237 net_address_module_info* addressModule = domain->address_module;
238
239 // compute and check the checksum
240 if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
241 IPPROTO_ICMPV6) != 0)
242 return B_BAD_DATA;
243
244 switch (header.icmp6_type) {
245 case ICMP6_ECHO_REPLY:
246 break;
247
248 case ICMP6_ECHO_REQUEST:
249 {
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;
256 }
257
258 net_buffer *reply = gBufferModule->duplicate(buffer);
259 if (reply == NULL)
260 return B_NO_MEMORY;
261
262 gBufferModule->swap_addresses(reply);
263
264 // There already is an ICMP header, and we'll reuse it
265 NetBufferHeaderReader<icmp6_hdr> header(reply);
266
267 header->icmp6_type = ICMP6_ECHO_REPLY;
268 header->icmp6_code = 0;
269 header->icmp6_cksum = 0;
270
271 header.Sync();
272
273 *ICMP6ChecksumField(reply) = Checksum::PseudoHeader(addressModule,
274 gBufferModule, buffer, IPPROTO_ICMPV6);
275
276 status_t status = domain->module->send_data(NULL, reply);
277 if (status < B_OK) {
278 gBufferModule->free(reply);
279 return status;
280 }
281 }
282
283 default:
284 // unrecognized messages go to neighbor discovery protocol handler
285 return sIPv6NDPModule->receive_data(buffer);
286 }
287
288 gBufferModule->free(buffer);
289 return B_OK;
290 }
291
292
293 status_t
icmp6_deliver_data(net_protocol * protocol,net_buffer * buffer)294 icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
295 {
296 // TODO: does this look OK?
297 return icmp6_receive_data(buffer);
298 }
299
300
301 status_t
icmp6_error_received(net_error code,net_buffer * data)302 icmp6_error_received(net_error code, net_buffer* data)
303 {
304 return B_ERROR;
305 }
306
307
308 status_t
icmp6_error_reply(net_protocol * protocol,net_buffer * buffer,net_error error,net_error_data * errorData)309 icmp6_error_reply(net_protocol* protocol, net_buffer* buffer, net_error error,
310 net_error_data* errorData)
311 {
312 return B_ERROR;
313 }
314
315
316 // #pragma mark -
317
318
319 static status_t
icmp6_init()320 icmp6_init()
321 {
322 sStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6,
323 "network/protocols/icmp6/v1",
324 "network/protocols/ipv6/v1",
325 NULL);
326
327 sStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_ICMPV6,
328 "network/protocols/icmp6/v1");
329
330 return B_OK;
331 }
332
333
334 static status_t
icmp6_std_ops(int32 op,...)335 icmp6_std_ops(int32 op, ...)
336 {
337 switch (op) {
338 case B_MODULE_INIT:
339 return icmp6_init();
340
341 case B_MODULE_UNINIT:
342 return B_OK;
343
344 default:
345 return B_ERROR;
346 }
347 }
348
349
350 net_protocol_module_info sICMP6Module = {
351 {
352 "network/protocols/icmp6/v1",
353 0,
354 icmp6_std_ops
355 },
356 NET_PROTOCOL_ATOMIC_MESSAGES,
357
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()
388 };
389
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},
395 {}
396 };
397
398 module_info *modules[] = {
399 (module_info *)&sICMP6Module,
400 NULL
401 };
402