source: mainline/uspace/srv/net/tl/udp/udp.c@ 6092b56e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6092b56e was 6092b56e, checked in by Jakub Jermar <jakub@…>, 15 years ago

Fix dangerous type casts.

  • Property mode set to 100644
File size: 23.5 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup udp
30 * @{
31 */
32
33/** @file
34 * UDP module implementation.
35 * @see udp.h
36 */
37
38#include <async.h>
39#include <fibril_synch.h>
40#include <malloc.h>
41#include <stdio.h>
42
43#include <ipc/ipc.h>
44#include <ipc/services.h>
45
46#include "../../err.h"
47#include "../../messages.h"
48#include "../../modules.h"
49
50#include "../../structures/dynamic_fifo.h"
51#include "../../structures/packet/packet_client.h"
52
53#include "../../include/checksum.h"
54#include "../../include/in.h"
55#include "../../include/in6.h"
56#include "../../include/inet.h"
57#include "../../include/ip_client.h"
58#include "../../include/ip_interface.h"
59#include "../../include/ip_protocols.h"
60#include "../../include/icmp_client.h"
61#include "../../include/icmp_interface.h"
62#include "../../include/net_interface.h"
63#include "../../include/socket_codes.h"
64#include "../../include/socket_errno.h"
65
66#include "../../socket/socket_core.h"
67#include "../../socket/socket_messages.h"
68
69#include "../tl_common.h"
70#include "../tl_messages.h"
71
72#include "udp.h"
73#include "udp_header.h"
74#include "udp_module.h"
75
76/** Default UDP checksum computing.
77 */
78#define NET_DEFAULT_UDP_CHECKSUM_COMPUTING true
79
80/** Default UDP autobind when sending via unbound sockets.
81 */
82#define NET_DEFAULT_UDP_AUTOBINDING true
83
84/** Maximum UDP fragment size.
85 */
86#define MAX_UDP_FRAGMENT_SIZE 65535
87
88/** Free ports pool start.
89 */
90#define UDP_FREE_PORTS_START 1025
91
92/** Free ports pool end.
93 */
94#define UDP_FREE_PORTS_END 65535
95
96/** Processes the received UDP packet queue.
97 * Is used as an entry point from the underlying IP module.
98 * Locks the global lock and calls udp_process_packet() function.
99 * @param[in] device_id The receiving device identifier.
100 * @param[in,out] packet The received packet queue.
101 * @param receiver The target service. Ignored parameter.
102 * @param[in] error The packet error reporting service. Prefixes the received packet.
103 * @returns EOK on success.
104 * @returns Other error codes as defined for the udp_process_packet() function.
105 */
106int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error);
107
108/** Processes the received UDP packet queue.
109 * Notifies the destination socket application.
110 * Releases the packet on error or sends an ICMP error notification..
111 * @param[in] device_id The receiving device identifier.
112 * @param[in,out] packet The received packet queue.
113 * @param[in] error The packet error reporting service. Prefixes the received packet.
114 * @returns EOK on success.
115 * @returns EINVAL if the packet is not valid.
116 * @returns EINVAL if the stored packet address is not the an_addr_t.
117 * @returns EINVAL if the packet does not contain any data.
118 * @returns NO_DATA if the packet content is shorter than the user datagram header.
119 * @returns ENOMEM if there is not enough memory left.
120 * @returns EADDRNOTAVAIL if the destination socket does not exist.
121 * @returns Other error codes as defined for the ip_client_process_packet() function.
122 */
123int udp_process_packet(device_id_t device_id, packet_t packet, services_t error);
124
125/** Releases the packet and returns the result.
126 * @param[in] packet The packet queue to be released.
127 * @param[in] result The result to be returned.
128 * @return The result parameter.
129 */
130int udp_release_and_return(packet_t packet, int result);
131
132/** @name Socket messages processing functions
133 */
134/*@{*/
135
136/** Processes the socket client messages.
137 * Runs until the client module disconnects.
138 * @param[in] callid The message identifier.
139 * @param[in] call The message parameters.
140 * @returns EOK on success.
141 * @see socket.h
142 */
143int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call);
144
145/** Sends data from the socket to the remote address.
146 * Binds the socket to a free port if not already connected/bound.
147 * Handles the NET_SOCKET_SENDTO message.
148 * Supports AF_INET and AF_INET6 address families.
149 * @param[in,out] local_sockets The application local sockets.
150 * @param[in] socket_id Socket identifier.
151 * @param[in] addr The destination address.
152 * @param[in] addrlen The address length.
153 * @param[in] fragments The number of data fragments.
154 * @param[out] data_fragment_size The data fragment size in bytes.
155 * @param[in] flags Various send flags.
156 * @returns EOK on success.
157 * @returns EAFNOTSUPPORT if the address family is not supported.
158 * @returns ENOTSOCK if the socket is not found.
159 * @returns EINVAL if the address is invalid.
160 * @returns ENOTCONN if the sending socket is not and cannot be bound.
161 * @returns ENOMEM if there is not enough memory left.
162 * @returns Other error codes as defined for the socket_read_packet_data() function.
163 * @returns Other error codes as defined for the ip_client_prepare_packet() function.
164 * @returns Other error codes as defined for the ip_send_msg() function.
165 */
166int udp_sendto_message(socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags);
167
168/** Receives data to the socket.
169 * Handles the NET_SOCKET_RECVFROM message.
170 * Replies the source address as well.
171 * @param[in] local_sockets The application local sockets.
172 * @param[in] socket_id Socket identifier.
173 * @param[in] flags Various receive flags.
174 * @param[out] addrlen The source address length.
175 * @returns The number of bytes received.
176 * @returns ENOTSOCK if the socket is not found.
177 * @returns NO_DATA if there are no received packets or data.
178 * @returns ENOMEM if there is not enough memory left.
179 * @returns EINVAL if the received address is not an IP address.
180 * @returns Other error codes as defined for the packet_translate() function.
181 * @returns Other error codes as defined for the data_reply() function.
182 */
183int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen);
184
185/*@}*/
186
187/** UDP global data.
188 */
189udp_globals_t udp_globals;
190
191int udp_initialize(async_client_conn_t client_connection){
192 ERROR_DECLARE;
193
194 measured_string_t names[] = {{str_dup("UDP_CHECKSUM_COMPUTING"), 22}, {str_dup("UDP_AUTOBINDING"), 15}};
195 measured_string_ref configuration;
196 size_t count = sizeof(names) / sizeof(measured_string_t);
197 char * data;
198
199 fibril_rwlock_initialize(&udp_globals.lock);
200 fibril_rwlock_write_lock(&udp_globals.lock);
201 udp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
202 udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg);
203 if(udp_globals.ip_phone < 0){
204 return udp_globals.ip_phone;
205 }
206 // read default packet dimensions
207 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension));
208 ERROR_PROPAGATE(socket_ports_initialize(&udp_globals.sockets));
209 if(ERROR_OCCURRED(packet_dimensions_initialize(&udp_globals.dimensions))){
210 socket_ports_destroy(&udp_globals.sockets);
211 return ERROR_CODE;
212 }
213 udp_globals.packet_dimension.prefix += sizeof(udp_header_t);
214 udp_globals.packet_dimension.content -= sizeof(udp_header_t);
215 udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
216 // get configuration
217 udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING;
218 udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING;
219 configuration = &names[0];
220 ERROR_PROPAGATE(net_get_conf_req(udp_globals.net_phone, &configuration, count, &data));
221 if(configuration){
222 if(configuration[0].value){
223 udp_globals.checksum_computing = (configuration[0].value[0] == 'y');
224 }
225 if(configuration[1].value){
226 udp_globals.autobinding = (configuration[1].value[0] == 'y');
227 }
228 net_free_settings(configuration, data);
229 }
230 fibril_rwlock_write_unlock(&udp_globals.lock);
231 return EOK;
232}
233
234int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){
235 int result;
236
237 fibril_rwlock_write_lock(&udp_globals.lock);
238 result = udp_process_packet(device_id, packet, error);
239 if(result != EOK){
240 fibril_rwlock_write_unlock(&udp_globals.lock);
241 }
242
243 return result;
244}
245
246int udp_process_packet(device_id_t device_id, packet_t packet, services_t error){
247 ERROR_DECLARE;
248
249 size_t length;
250 size_t offset;
251 int result;
252 udp_header_ref header;
253 socket_core_ref socket;
254 packet_t next_packet;
255 size_t total_length;
256 uint32_t checksum;
257 int fragments;
258 packet_t tmp_packet;
259 icmp_type_t type;
260 icmp_code_t code;
261 ip_pseudo_header_ref ip_header;
262 struct sockaddr * src;
263 struct sockaddr * dest;
264 packet_dimension_ref packet_dimension;
265
266 if(error){
267 switch(error){
268 case SERVICE_ICMP:
269 // ignore error
270 // length = icmp_client_header_length(packet);
271 // process error
272 result = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
273 if(result < 0){
274 return udp_release_and_return(packet, result);
275 }
276 length = (size_t) result;
277 if(ERROR_OCCURRED(packet_trim(packet, length, 0))){
278 return udp_release_and_return(packet, ERROR_CODE);
279 }
280 break;
281 default:
282 return udp_release_and_return(packet, ENOTSUP);
283 }
284 }
285 // TODO process received ipopts?
286 result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
287 if(result < 0){
288 return udp_release_and_return(packet, result);
289 }
290 offset = (size_t) result;
291
292 length = packet_get_data_length(packet);
293 if(length <= 0){
294 return udp_release_and_return(packet, EINVAL);
295 }
296 if(length < UDP_HEADER_SIZE + offset){
297 return udp_release_and_return(packet, NO_DATA);
298 }
299
300 // trim all but UDP header
301 if(ERROR_OCCURRED(packet_trim(packet, offset, 0))){
302 return udp_release_and_return(packet, ERROR_CODE);
303 }
304
305 // get udp header
306 header = (udp_header_ref) packet_get_data(packet);
307 if(! header){
308 return udp_release_and_return(packet, NO_DATA);
309 }
310 // find the destination socket
311 socket = socket_port_find(&udp_globals.sockets, ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING, 0);
312 if(! socket){
313 if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){
314 icmp_destination_unreachable_msg(udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet);
315 }
316 return EADDRNOTAVAIL;
317 }
318
319 // count the received packet fragments
320 next_packet = packet;
321 fragments = 0;
322 total_length = ntohs(header->total_length);
323 // compute header checksum if set
324 if(header->checksum && (! error)){
325 result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
326 if(result <= 0){
327 return udp_release_and_return(packet, result);
328 }
329 if(ERROR_OCCURRED(ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest, result, total_length, &ip_header, &length))){
330 return udp_release_and_return(packet, ERROR_CODE);
331 }else{
332 checksum = compute_checksum(0, ip_header, length);
333 // the udp header checksum will be added with the first fragment later
334 free(ip_header);
335 }
336 }else{
337 header->checksum = 0;
338 checksum = 0;
339 }
340
341 do{
342 ++ fragments;
343 length = packet_get_data_length(next_packet);
344 if(length <= 0){
345 return udp_release_and_return(packet, NO_DATA);
346 }
347 if(total_length < length){
348 if(ERROR_OCCURRED(packet_trim(next_packet, 0, length - total_length))){
349 return udp_release_and_return(packet, ERROR_CODE);
350 }
351 // add partial checksum if set
352 if(header->checksum){
353 checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet));
354 }
355 // relese the rest of the packet fragments
356 tmp_packet = pq_next(next_packet);
357 while(tmp_packet){
358 next_packet = pq_detach(tmp_packet);
359 pq_release(udp_globals.net_phone, packet_get_id(tmp_packet));
360 tmp_packet = next_packet;
361 }
362 // exit the loop
363 break;
364 }
365 total_length -= length;
366 // add partial checksum if set
367 if(header->checksum){
368 checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet));
369 }
370 }while((next_packet = pq_next(next_packet)) && (total_length > 0));
371
372 // check checksum
373 if(header->checksum){
374 if(flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO){
375 if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){
376 // checksum error ICMP
377 icmp_parameter_problem_msg(udp_globals.icmp_phone, ICMP_PARAM_POINTER, ((size_t) ((void *) &header->checksum)) - ((size_t) ((void *) header)), packet);
378 }
379 return EINVAL;
380 }
381 }
382
383 // queue the received packet
384 if(ERROR_OCCURRED(dyn_fifo_push(&socket->received, packet_get_id(packet), SOCKET_MAX_RECEIVED_SIZE))
385 || ERROR_OCCURRED(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension))){
386 return udp_release_and_return(packet, ERROR_CODE);
387 }
388
389 // notify the destination socket
390 fibril_rwlock_write_unlock(&udp_globals.lock);
391 async_msg_5(socket->phone, NET_SOCKET_RECEIVED, (ipcarg_t) socket->socket_id, packet_dimension->content, 0, 0, (ipcarg_t) fragments);
392 return EOK;
393}
394
395int udp_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
396 ERROR_DECLARE;
397
398 packet_t packet;
399
400 *answer_count = 0;
401 switch(IPC_GET_METHOD(*call)){
402 case NET_TL_RECEIVED:
403 if(! ERROR_OCCURRED(packet_translate(udp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
404 ERROR_CODE = udp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_UDP, IPC_GET_ERROR(call));
405 }
406 return ERROR_CODE;
407 case IPC_M_CONNECT_TO_ME:
408 return udp_process_client_messages(callid, * call);
409 }
410 return ENOTSUP;
411}
412
413int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
414 int res;
415 bool keep_on_going = true;
416 socket_cores_t local_sockets;
417 int app_phone = IPC_GET_PHONE(&call);
418 struct sockaddr * addr;
419 int socket_id;
420 size_t addrlen;
421 ipc_call_t answer;
422 int answer_count;
423 packet_dimension_ref packet_dimension;
424
425 /*
426 * Accept the connection
427 * - Answer the first IPC_M_CONNECT_TO_ME call.
428 */
429 res = EOK;
430 answer_count = 0;
431
432 // The client connection is only in one fibril and therefore no additional locks are needed.
433
434 socket_cores_initialize(&local_sockets);
435
436 while(keep_on_going){
437
438 // answer the call
439 answer_call(callid, res, &answer, answer_count);
440
441 // refresh data
442 refresh_answer(&answer, &answer_count);
443
444 // get the next call
445 callid = async_get_call(&call);
446
447 // process the call
448 switch(IPC_GET_METHOD(call)){
449 case IPC_M_PHONE_HUNGUP:
450 keep_on_going = false;
451 res = EHANGUP;
452 break;
453 case NET_SOCKET:
454 socket_id = SOCKET_GET_SOCKET_ID(call);
455 res = socket_create(&local_sockets, app_phone, NULL, &socket_id);
456 *SOCKET_SET_SOCKET_ID(answer) = socket_id;
457
458 if(res == EOK){
459 if(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, DEVICE_INVALID_ID, &packet_dimension) == EOK){
460 *SOCKET_SET_DATA_FRAGMENT_SIZE(answer) = packet_dimension->content;
461 }
462// *SOCKET_SET_DATA_FRAGMENT_SIZE(answer) = MAX_UDP_FRAGMENT_SIZE;
463 *SOCKET_SET_HEADER_SIZE(answer) = UDP_HEADER_SIZE;
464 answer_count = 3;
465 }
466 break;
467 case NET_SOCKET_BIND:
468 res = data_receive((void **) &addr, &addrlen);
469 if(res == EOK){
470 fibril_rwlock_write_lock(&udp_globals.lock);
471 res = socket_bind(&local_sockets, &udp_globals.sockets, SOCKET_GET_SOCKET_ID(call), addr, addrlen, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port);
472 fibril_rwlock_write_unlock(&udp_globals.lock);
473 free(addr);
474 }
475 break;
476 case NET_SOCKET_SENDTO:
477 res = data_receive((void **) &addr, &addrlen);
478 if(res == EOK){
479 fibril_rwlock_write_lock(&udp_globals.lock);
480 res = udp_sendto_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS(call), SOCKET_SET_DATA_FRAGMENT_SIZE(answer), SOCKET_GET_FLAGS(call));
481 if(res != EOK){
482 fibril_rwlock_write_unlock(&udp_globals.lock);
483 }else{
484 answer_count = 2;
485 }
486 free(addr);
487 }
488 break;
489 case NET_SOCKET_RECVFROM:
490 fibril_rwlock_write_lock(&udp_globals.lock);
491 res = udp_recvfrom_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call), &addrlen);
492 fibril_rwlock_write_unlock(&udp_globals.lock);
493 if(res > 0){
494 *SOCKET_SET_READ_DATA_LENGTH(answer) = res;
495 *SOCKET_SET_ADDRESS_LENGTH(answer) = addrlen;
496 answer_count = 3;
497 res = EOK;
498 }
499 break;
500 case NET_SOCKET_CLOSE:
501 fibril_rwlock_write_lock(&udp_globals.lock);
502 res = socket_destroy(udp_globals.net_phone, SOCKET_GET_SOCKET_ID(call), &local_sockets, &udp_globals.sockets, NULL);
503 fibril_rwlock_write_unlock(&udp_globals.lock);
504 break;
505 case NET_SOCKET_GETSOCKOPT:
506 case NET_SOCKET_SETSOCKOPT:
507 default:
508 res = ENOTSUP;
509 break;
510 }
511 }
512
513 // release the application phone
514 ipc_hangup(app_phone);
515
516 // release all local sockets
517 socket_cores_release(udp_globals.net_phone, &local_sockets, &udp_globals.sockets, NULL);
518
519 return res;
520}
521
522int udp_sendto_message(socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags){
523 ERROR_DECLARE;
524
525 socket_core_ref socket;
526 packet_t packet;
527 packet_t next_packet;
528 udp_header_ref header;
529 int index;
530 size_t total_length;
531 int result;
532 uint16_t dest_port;
533 uint32_t checksum;
534 ip_pseudo_header_ref ip_header;
535 size_t headerlen;
536 device_id_t device_id;
537 packet_dimension_ref packet_dimension;
538
539 ERROR_PROPAGATE(tl_get_address_port(addr, addrlen, &dest_port));
540
541 socket = socket_cores_find(local_sockets, socket_id);
542 if(! socket){
543 return ENOTSOCK;
544 }
545
546 if((socket->port <= 0) && udp_globals.autobinding){
547 // bind the socket to a random free port if not bound
548// do{
549 // try to find a free port
550// fibril_rwlock_read_unlock(&udp_globals.lock);
551// fibril_rwlock_write_lock(&udp_globals.lock);
552 // might be changed in the meantime
553// if(socket->port <= 0){
554 if(ERROR_OCCURRED(socket_bind_free_port(&udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port))){
555// fibril_rwlock_write_unlock(&udp_globals.lock);
556// fibril_rwlock_read_lock(&udp_globals.lock);
557 return ERROR_CODE;
558 }
559 // set the next port as the search starting port number
560 udp_globals.last_used_port = socket->port;
561// }
562// fibril_rwlock_write_unlock(&udp_globals.lock);
563// fibril_rwlock_read_lock(&udp_globals.lock);
564 // might be changed in the meantime
565// }while(socket->port <= 0);
566 }
567
568 if(udp_globals.checksum_computing){
569 if(ERROR_OCCURRED(ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr, addrlen, &device_id, &ip_header, &headerlen))){
570 return udp_release_and_return(packet, ERROR_CODE);
571 }
572 // get the device packet dimension
573// ERROR_PROPAGATE(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension));
574 }
575// }else{
576 // do not ask all the time
577 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension));
578 packet_dimension = &udp_globals.packet_dimension;
579// }
580
581 // read the first packet fragment
582 result = tl_socket_read_packet_data(udp_globals.net_phone, &packet, UDP_HEADER_SIZE, packet_dimension, addr, addrlen);
583 if(result < 0){
584 return result;
585 }
586 total_length = (size_t) result;
587 if(udp_globals.checksum_computing){
588 checksum = compute_checksum(0, packet_get_data(packet), packet_get_data_length(packet));
589 }else{
590 checksum = 0;
591 }
592 // prefix the udp header
593 header = PACKET_PREFIX(packet, udp_header_t);
594 if(! header){
595 return udp_release_and_return(packet, ENOMEM);
596 }
597 bzero(header, sizeof(*header));
598 // read the rest of the packet fragments
599 for(index = 1; index < fragments; ++ index){
600 result = tl_socket_read_packet_data(udp_globals.net_phone, &next_packet, 0, packet_dimension, addr, addrlen);
601 if(result < 0){
602 return udp_release_and_return(packet, result);
603 }
604 if(ERROR_OCCURRED(pq_add(&packet, next_packet, index, 0))){
605 return udp_release_and_return(packet, ERROR_CODE);
606 }
607 total_length += (size_t) result;
608 if(udp_globals.checksum_computing){
609 checksum = compute_checksum(checksum, packet_get_data(next_packet), packet_get_data_length(next_packet));
610 }
611 }
612 // set the udp header
613 header->source_port = htons((socket->port > 0) ? socket->port : 0);
614 header->destination_port = htons(dest_port);
615 header->total_length = htons(total_length + sizeof(*header));
616 header->checksum = 0;
617 if(udp_globals.checksum_computing){
618 // update the pseudo header
619 if(ERROR_OCCURRED(ip_client_set_pseudo_header_data_length(ip_header, headerlen, total_length + UDP_HEADER_SIZE))){
620 free(ip_header);
621 return udp_release_and_return(packet, ERROR_CODE);
622 }
623 // finish the checksum computation
624 checksum = compute_checksum(checksum, ip_header, headerlen);
625 checksum = compute_checksum(checksum, (uint8_t *) header, sizeof(*header));
626 header->checksum = htons(flip_checksum(compact_checksum(checksum)));
627 free(ip_header);
628 }else{
629 device_id = DEVICE_INVALID_ID;
630 }
631 // prepare the first packet fragment
632 if(ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0))){
633 return udp_release_and_return(packet, ERROR_CODE);
634 }
635 // send the packet
636 fibril_rwlock_write_unlock(&udp_globals.lock);
637 ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0);
638 return EOK;
639}
640
641int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen){
642 ERROR_DECLARE;
643
644 socket_core_ref socket;
645 int packet_id;
646 packet_t packet;
647 udp_header_ref header;
648 struct sockaddr * addr;
649 size_t length;
650 uint8_t * data;
651 int result;
652
653 // find the socket
654 socket = socket_cores_find(local_sockets, socket_id);
655 if(! socket){
656 return ENOTSOCK;
657 }
658 // get the next received packet
659 packet_id = dyn_fifo_value(&socket->received);
660 if(packet_id < 0){
661 return NO_DATA;
662 }
663 ERROR_PROPAGATE(packet_translate(udp_globals.net_phone, &packet, packet_id));
664 // get udp header
665 data = packet_get_data(packet);
666 if(! data){
667 pq_release(udp_globals.net_phone, packet_id);
668 return NO_DATA;
669 }
670 header = (udp_header_ref) data;
671
672 // set the source address port
673 result = packet_get_addr(packet, (uint8_t **) &addr, NULL);
674 if(ERROR_OCCURRED(tl_set_address_port(addr, result, ntohs(header->source_port)))){
675 pq_release(udp_globals.net_phone, packet_id);
676 return ERROR_CODE;
677 }
678 *addrlen = (size_t) result;
679 // send the source address
680 ERROR_PROPAGATE(data_reply(addr, * addrlen));
681
682 // trim the header
683 ERROR_PROPAGATE(packet_trim(packet, UDP_HEADER_SIZE, 0));
684
685 // reply the packets
686 ERROR_PROPAGATE(socket_reply_packets(packet, &length));
687
688 // release the packet
689 dyn_fifo_pop(&socket->received);
690 pq_release(udp_globals.net_phone, packet_get_id(packet));
691 // return the total length
692 return (int) length;
693}
694
695int udp_release_and_return(packet_t packet, int result){
696 pq_release(udp_globals.net_phone, packet_get_id(packet));
697 return result;
698}
699
700/** @}
701 */
Note: See TracBrowser for help on using the repository browser.