source: mainline/uspace/srv/net/tl/udp/udp.c@ 849ed54

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 849ed54 was 849ed54, checked in by Martin Decky <martin@…>, 15 years ago

Networking work:
Split the networking stack into end-user library (libsocket) and two helper libraries (libnet and libnetif).
Don't use over-the-hand compiling and linking, but rather separation of conserns.
There might be still some issues and the non-modular networking architecture is currently broken, but this will be fixed soon.

  • Property mode set to 100644
File size: 24.9 KB
RevLine 
[21580dd]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#include <ipc/ipc.h>
43#include <ipc/services.h>
44
[849ed54]45#include <net_err.h>
46#include <net_messages.h>
47#include <net_modules.h>
48#include <adt/dynamic_fifo.h>
49#include <packet/packet_client.h>
50#include <net_checksum.h>
51#include <in.h>
52#include <in6.h>
53#include <inet.h>
54#include <ip_client.h>
55#include <ip_interface.h>
56#include <ip_protocols.h>
57#include <icmp_client.h>
58#include <icmp_interface.h>
59#include <net_interface.h>
60#include <socket_codes.h>
61#include <socket_errno.h>
62#include <socket_core.h>
63#include <socket_messages.h>
64#include <tl_common.h>
65#include <tl_messages.h>
[21580dd]66
67#include "udp.h"
68#include "udp_header.h"
69#include "udp_module.h"
70
[849ed54]71/** UDP module name.
72 */
73#define NAME "UDP protocol"
74
[21580dd]75/** Default UDP checksum computing.
76 */
77#define NET_DEFAULT_UDP_CHECKSUM_COMPUTING true
78
79/** Default UDP autobind when sending via unbound sockets.
80 */
81#define NET_DEFAULT_UDP_AUTOBINDING true
82
83/** Maximum UDP fragment size.
84 */
85#define MAX_UDP_FRAGMENT_SIZE 65535
86
87/** Free ports pool start.
88 */
89#define UDP_FREE_PORTS_START 1025
90
91/** Free ports pool end.
92 */
93#define UDP_FREE_PORTS_END 65535
94
95/** Processes the received UDP packet queue.
96 * Is used as an entry point from the underlying IP module.
97 * Locks the global lock and calls udp_process_packet() function.
[ede63e4]98 * @param[in] device_id The receiving device identifier.
[21580dd]99 * @param[in,out] packet The received packet queue.
100 * @param receiver The target service. Ignored parameter.
101 * @param[in] error The packet error reporting service. Prefixes the received packet.
102 * @returns EOK on success.
103 * @returns Other error codes as defined for the udp_process_packet() function.
104 */
[aadf01e]105int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error);
[21580dd]106
107/** Processes the received UDP packet queue.
108 * Notifies the destination socket application.
109 * Releases the packet on error or sends an ICMP error notification..
[ede63e4]110 * @param[in] device_id The receiving device identifier.
[21580dd]111 * @param[in,out] packet The received packet queue.
112 * @param[in] error The packet error reporting service. Prefixes the received packet.
113 * @returns EOK on success.
114 * @returns EINVAL if the packet is not valid.
115 * @returns EINVAL if the stored packet address is not the an_addr_t.
116 * @returns EINVAL if the packet does not contain any data.
117 * @returns NO_DATA if the packet content is shorter than the user datagram header.
118 * @returns ENOMEM if there is not enough memory left.
119 * @returns EADDRNOTAVAIL if the destination socket does not exist.
120 * @returns Other error codes as defined for the ip_client_process_packet() function.
121 */
[aadf01e]122int udp_process_packet(device_id_t device_id, packet_t packet, services_t error);
[21580dd]123
124/** Releases the packet and returns the result.
125 * @param[in] packet The packet queue to be released.
126 * @param[in] result The result to be returned.
127 * @return The result parameter.
128 */
[aadf01e]129int udp_release_and_return(packet_t packet, int result);
[21580dd]130
131/** @name Socket messages processing functions
132 */
133/*@{*/
134
135/** Processes the socket client messages.
136 * Runs until the client module disconnects.
137 * @param[in] callid The message identifier.
138 * @param[in] call The message parameters.
139 * @returns EOK on success.
140 * @see socket.h
141 */
[aadf01e]142int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call);
[21580dd]143
144/** Sends data from the socket to the remote address.
145 * Binds the socket to a free port if not already connected/bound.
146 * Handles the NET_SOCKET_SENDTO message.
147 * Supports AF_INET and AF_INET6 address families.
148 * @param[in,out] local_sockets The application local sockets.
149 * @param[in] socket_id Socket identifier.
150 * @param[in] addr The destination address.
151 * @param[in] addrlen The address length.
152 * @param[in] fragments The number of data fragments.
[ede63e4]153 * @param[out] data_fragment_size The data fragment size in bytes.
[21580dd]154 * @param[in] flags Various send flags.
155 * @returns EOK on success.
156 * @returns EAFNOTSUPPORT if the address family is not supported.
157 * @returns ENOTSOCK if the socket is not found.
158 * @returns EINVAL if the address is invalid.
159 * @returns ENOTCONN if the sending socket is not and cannot be bound.
160 * @returns ENOMEM if there is not enough memory left.
161 * @returns Other error codes as defined for the socket_read_packet_data() function.
162 * @returns Other error codes as defined for the ip_client_prepare_packet() function.
163 * @returns Other error codes as defined for the ip_send_msg() function.
164 */
[aadf01e]165int 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);
[21580dd]166
167/** Receives data to the socket.
168 * Handles the NET_SOCKET_RECVFROM message.
169 * Replies the source address as well.
170 * @param[in] local_sockets The application local sockets.
171 * @param[in] socket_id Socket identifier.
172 * @param[in] flags Various receive flags.
173 * @param[out] addrlen The source address length.
174 * @returns The number of bytes received.
175 * @returns ENOTSOCK if the socket is not found.
176 * @returns NO_DATA if there are no received packets or data.
177 * @returns ENOMEM if there is not enough memory left.
178 * @returns EINVAL if the received address is not an IP address.
179 * @returns Other error codes as defined for the packet_translate() function.
180 * @returns Other error codes as defined for the data_reply() function.
181 */
[aadf01e]182int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen);
[21580dd]183
184/*@}*/
185
186/** UDP global data.
187 */
188udp_globals_t udp_globals;
189
[aadf01e]190int udp_initialize(async_client_conn_t client_connection){
[21580dd]191 ERROR_DECLARE;
192
[aadf01e]193 measured_string_t names[] = {{str_dup("UDP_CHECKSUM_COMPUTING"), 22}, {str_dup("UDP_AUTOBINDING"), 15}};
194 measured_string_ref configuration;
195 size_t count = sizeof(names) / sizeof(measured_string_t);
196 char * data;
[21580dd]197
[aadf01e]198 fibril_rwlock_initialize(&udp_globals.lock);
199 fibril_rwlock_write_lock(&udp_globals.lock);
200 udp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
201 udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg);
202 if(udp_globals.ip_phone < 0){
[21580dd]203 return udp_globals.ip_phone;
204 }
205 // read default packet dimensions
[aadf01e]206 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension));
207 ERROR_PROPAGATE(socket_ports_initialize(&udp_globals.sockets));
208 if(ERROR_OCCURRED(packet_dimensions_initialize(&udp_globals.dimensions))){
209 socket_ports_destroy(&udp_globals.sockets);
[21580dd]210 return ERROR_CODE;
211 }
[aadf01e]212 udp_globals.packet_dimension.prefix += sizeof(udp_header_t);
213 udp_globals.packet_dimension.content -= sizeof(udp_header_t);
[21580dd]214 udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
215 // get configuration
216 udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING;
217 udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING;
[aadf01e]218 configuration = &names[0];
219 ERROR_PROPAGATE(net_get_conf_req(udp_globals.net_phone, &configuration, count, &data));
220 if(configuration){
221 if(configuration[0].value){
222 udp_globals.checksum_computing = (configuration[0].value[0] == 'y');
[21580dd]223 }
[aadf01e]224 if(configuration[1].value){
225 udp_globals.autobinding = (configuration[1].value[0] == 'y');
[21580dd]226 }
[aadf01e]227 net_free_settings(configuration, data);
[21580dd]228 }
[aadf01e]229 fibril_rwlock_write_unlock(&udp_globals.lock);
[21580dd]230 return EOK;
231}
232
[aadf01e]233int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){
234 int result;
[21580dd]235
[aadf01e]236 fibril_rwlock_write_lock(&udp_globals.lock);
237 result = udp_process_packet(device_id, packet, error);
238 if(result != EOK){
239 fibril_rwlock_write_unlock(&udp_globals.lock);
[21580dd]240 }
241
242 return result;
243}
244
[aadf01e]245int udp_process_packet(device_id_t device_id, packet_t packet, services_t error){
[21580dd]246 ERROR_DECLARE;
247
[aadf01e]248 size_t length;
249 size_t offset;
250 int result;
251 udp_header_ref header;
252 socket_core_ref socket;
253 packet_t next_packet;
254 size_t total_length;
255 uint32_t checksum;
256 int fragments;
257 packet_t tmp_packet;
258 icmp_type_t type;
259 icmp_code_t code;
260 ip_pseudo_header_ref ip_header;
261 struct sockaddr * src;
262 struct sockaddr * dest;
263 packet_dimension_ref packet_dimension;
264
265 if(error){
266 switch(error){
[21580dd]267 case SERVICE_ICMP:
268 // ignore error
[aadf01e]269 // length = icmp_client_header_length(packet);
[21580dd]270 // process error
[aadf01e]271 result = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
272 if(result < 0){
273 return udp_release_and_return(packet, result);
[21580dd]274 }
[aadf01e]275 length = (size_t) result;
276 if(ERROR_OCCURRED(packet_trim(packet, length, 0))){
277 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]278 }
279 break;
280 default:
[aadf01e]281 return udp_release_and_return(packet, ENOTSUP);
[21580dd]282 }
283 }
284 // TODO process received ipopts?
[aadf01e]285 result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
286 if(result < 0){
287 return udp_release_and_return(packet, result);
[21580dd]288 }
[aadf01e]289 offset = (size_t) result;
[21580dd]290
[aadf01e]291 length = packet_get_data_length(packet);
292 if(length <= 0){
293 return udp_release_and_return(packet, EINVAL);
[21580dd]294 }
[aadf01e]295 if(length < UDP_HEADER_SIZE + offset){
296 return udp_release_and_return(packet, NO_DATA);
[21580dd]297 }
298
299 // trim all but UDP header
[aadf01e]300 if(ERROR_OCCURRED(packet_trim(packet, offset, 0))){
301 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]302 }
303
304 // get udp header
[aadf01e]305 header = (udp_header_ref) packet_get_data(packet);
306 if(! header){
307 return udp_release_and_return(packet, NO_DATA);
[21580dd]308 }
309 // find the destination socket
[aadf01e]310 socket = socket_port_find(&udp_globals.sockets, ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING, 0);
311 if(! socket){
312 if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){
313 icmp_destination_unreachable_msg(udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet);
[21580dd]314 }
315 return EADDRNOTAVAIL;
316 }
317
318 // count the received packet fragments
319 next_packet = packet;
320 fragments = 0;
[aadf01e]321 total_length = ntohs(header->total_length);
[21580dd]322 // compute header checksum if set
[aadf01e]323 if(header->checksum && (! error)){
324 result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
325 if(result <= 0){
326 return udp_release_and_return(packet, result);
[21580dd]327 }
[aadf01e]328 if(ERROR_OCCURRED(ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest, result, total_length, &ip_header, &length))){
329 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]330 }else{
[aadf01e]331 checksum = compute_checksum(0, ip_header, length);
[21580dd]332 // the udp header checksum will be added with the first fragment later
[aadf01e]333 free(ip_header);
[21580dd]334 }
335 }else{
336 header->checksum = 0;
337 checksum = 0;
338 }
339
340 do{
341 ++ fragments;
[aadf01e]342 length = packet_get_data_length(next_packet);
343 if(length <= 0){
344 return udp_release_and_return(packet, NO_DATA);
[21580dd]345 }
[aadf01e]346 if(total_length < length){
347 if(ERROR_OCCURRED(packet_trim(next_packet, 0, length - total_length))){
348 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]349 }
350 // add partial checksum if set
[aadf01e]351 if(header->checksum){
352 checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet));
[21580dd]353 }
354 // relese the rest of the packet fragments
[aadf01e]355 tmp_packet = pq_next(next_packet);
356 while(tmp_packet){
357 next_packet = pq_detach(tmp_packet);
358 pq_release(udp_globals.net_phone, packet_get_id(tmp_packet));
[21580dd]359 tmp_packet = next_packet;
360 }
361 // exit the loop
362 break;
363 }
364 total_length -= length;
365 // add partial checksum if set
[aadf01e]366 if(header->checksum){
367 checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet));
[21580dd]368 }
[aadf01e]369 }while((next_packet = pq_next(next_packet)) && (total_length > 0));
[21580dd]370
371 // check checksum
[aadf01e]372 if(header->checksum){
373 if(flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO){
374 if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){
[21580dd]375 // checksum error ICMP
[aadf01e]376 icmp_parameter_problem_msg(udp_globals.icmp_phone, ICMP_PARAM_POINTER, ((size_t) ((void *) &header->checksum)) - ((size_t) ((void *) header)), packet);
[21580dd]377 }
378 return EINVAL;
379 }
380 }
381
382 // queue the received packet
[aadf01e]383 if(ERROR_OCCURRED(dyn_fifo_push(&socket->received, packet_get_id(packet), SOCKET_MAX_RECEIVED_SIZE))
384 || ERROR_OCCURRED(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension))){
385 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]386 }
387
388 // notify the destination socket
[aadf01e]389 fibril_rwlock_write_unlock(&udp_globals.lock);
390 async_msg_5(socket->phone, NET_SOCKET_RECEIVED, (ipcarg_t) socket->socket_id, packet_dimension->content, 0, 0, (ipcarg_t) fragments);
[2e99277]391 return EOK;
[21580dd]392}
393
[aadf01e]394int udp_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
[21580dd]395 ERROR_DECLARE;
396
[aadf01e]397 packet_t packet;
[21580dd]398
[aadf01e]399 *answer_count = 0;
400 switch(IPC_GET_METHOD(*call)){
[21580dd]401 case NET_TL_RECEIVED:
[aadf01e]402 if(! ERROR_OCCURRED(packet_translate(udp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
403 ERROR_CODE = udp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_UDP, IPC_GET_ERROR(call));
[21580dd]404 }
405 return ERROR_CODE;
406 case IPC_M_CONNECT_TO_ME:
[aadf01e]407 return udp_process_client_messages(callid, * call);
[21580dd]408 }
409 return ENOTSUP;
410}
411
[aadf01e]412int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
413 int res;
414 bool keep_on_going = true;
415 socket_cores_t local_sockets;
416 int app_phone = IPC_GET_PHONE(&call);
417 struct sockaddr * addr;
[6092b56e]418 int socket_id;
[aadf01e]419 size_t addrlen;
[e417b96]420 size_t size;
[aadf01e]421 ipc_call_t answer;
422 int answer_count;
423 packet_dimension_ref packet_dimension;
[21580dd]424
425 /*
426 * Accept the connection
427 * - Answer the first IPC_M_CONNECT_TO_ME call.
428 */
[2e99277]429 res = EOK;
430 answer_count = 0;
[21580dd]431
432 // The client connection is only in one fibril and therefore no additional locks are needed.
433
[aadf01e]434 socket_cores_initialize(&local_sockets);
[21580dd]435
[aadf01e]436 while(keep_on_going){
[2e99277]437
438 // answer the call
[aadf01e]439 answer_call(callid, res, &answer, answer_count);
[2e99277]440
[21580dd]441 // refresh data
[aadf01e]442 refresh_answer(&answer, &answer_count);
[21580dd]443
[2e99277]444 // get the next call
[aadf01e]445 callid = async_get_call(&call);
[21580dd]446
[2e99277]447 // process the call
[aadf01e]448 switch(IPC_GET_METHOD(call)){
[21580dd]449 case IPC_M_PHONE_HUNGUP:
450 keep_on_going = false;
[2e99277]451 res = EHANGUP;
[21580dd]452 break;
453 case NET_SOCKET:
[6092b56e]454 socket_id = SOCKET_GET_SOCKET_ID(call);
455 res = socket_create(&local_sockets, app_phone, NULL, &socket_id);
[e417b96]456 SOCKET_SET_SOCKET_ID(answer, socket_id);
457
[aadf01e]458 if(res == EOK){
459 if(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, DEVICE_INVALID_ID, &packet_dimension) == EOK){
[e417b96]460 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, packet_dimension->content);
[ede63e4]461 }
[e417b96]462// SOCKET_SET_DATA_FRAGMENT_SIZE(answer, MAX_UDP_FRAGMENT_SIZE);
463 SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE);
[ede63e4]464 answer_count = 3;
465 }
[21580dd]466 break;
467 case NET_SOCKET_BIND:
[aadf01e]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);
[21580dd]474 }
475 break;
476 case NET_SOCKET_SENDTO:
[aadf01e]477 res = data_receive((void **) &addr, &addrlen);
478 if(res == EOK){
479 fibril_rwlock_write_lock(&udp_globals.lock);
[e417b96]480 res = udp_sendto_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS(call), &size, SOCKET_GET_FLAGS(call));
481 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
[aadf01e]482 if(res != EOK){
483 fibril_rwlock_write_unlock(&udp_globals.lock);
[ede63e4]484 }else{
485 answer_count = 2;
[21580dd]486 }
[aadf01e]487 free(addr);
[21580dd]488 }
489 break;
490 case NET_SOCKET_RECVFROM:
[aadf01e]491 fibril_rwlock_write_lock(&udp_globals.lock);
492 res = udp_recvfrom_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call), &addrlen);
493 fibril_rwlock_write_unlock(&udp_globals.lock);
494 if(res > 0){
[e417b96]495 SOCKET_SET_READ_DATA_LENGTH(answer, res);
496 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
[ede63e4]497 answer_count = 3;
[21580dd]498 res = EOK;
499 }
500 break;
501 case NET_SOCKET_CLOSE:
[aadf01e]502 fibril_rwlock_write_lock(&udp_globals.lock);
503 res = socket_destroy(udp_globals.net_phone, SOCKET_GET_SOCKET_ID(call), &local_sockets, &udp_globals.sockets, NULL);
504 fibril_rwlock_write_unlock(&udp_globals.lock);
[21580dd]505 break;
506 case NET_SOCKET_GETSOCKOPT:
507 case NET_SOCKET_SETSOCKOPT:
508 default:
509 res = ENOTSUP;
510 break;
511 }
512 }
513
[a8a13d0]514 // release the application phone
515 ipc_hangup(app_phone);
516
[21580dd]517 // release all local sockets
[aadf01e]518 socket_cores_release(udp_globals.net_phone, &local_sockets, &udp_globals.sockets, NULL);
[21580dd]519
[2e99277]520 return res;
[21580dd]521}
522
[aadf01e]523int 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){
[21580dd]524 ERROR_DECLARE;
525
[aadf01e]526 socket_core_ref socket;
527 packet_t packet;
528 packet_t next_packet;
529 udp_header_ref header;
530 int index;
531 size_t total_length;
532 int result;
533 uint16_t dest_port;
534 uint32_t checksum;
535 ip_pseudo_header_ref ip_header;
536 size_t headerlen;
537 device_id_t device_id;
538 packet_dimension_ref packet_dimension;
539
540 ERROR_PROPAGATE(tl_get_address_port(addr, addrlen, &dest_port));
541
542 socket = socket_cores_find(local_sockets, socket_id);
543 if(! socket){
544 return ENOTSOCK;
545 }
546
547 if((socket->port <= 0) && udp_globals.autobinding){
[21580dd]548 // bind the socket to a random free port if not bound
549// do{
550 // try to find a free port
[aadf01e]551// fibril_rwlock_read_unlock(&udp_globals.lock);
552// fibril_rwlock_write_lock(&udp_globals.lock);
[21580dd]553 // might be changed in the meantime
[aadf01e]554// if(socket->port <= 0){
555 if(ERROR_OCCURRED(socket_bind_free_port(&udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port))){
556// fibril_rwlock_write_unlock(&udp_globals.lock);
557// fibril_rwlock_read_lock(&udp_globals.lock);
[21580dd]558 return ERROR_CODE;
559 }
560 // set the next port as the search starting port number
561 udp_globals.last_used_port = socket->port;
562// }
[aadf01e]563// fibril_rwlock_write_unlock(&udp_globals.lock);
564// fibril_rwlock_read_lock(&udp_globals.lock);
[21580dd]565 // might be changed in the meantime
[aadf01e]566// }while(socket->port <= 0);
[21580dd]567 }
568
[aadf01e]569 if(udp_globals.checksum_computing){
570 if(ERROR_OCCURRED(ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr, addrlen, &device_id, &ip_header, &headerlen))){
571 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]572 }
573 // get the device packet dimension
[aadf01e]574// ERROR_PROPAGATE(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension));
[21580dd]575 }
576// }else{
577 // do not ask all the time
[aadf01e]578 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension));
579 packet_dimension = &udp_globals.packet_dimension;
[21580dd]580// }
581
582 // read the first packet fragment
[aadf01e]583 result = tl_socket_read_packet_data(udp_globals.net_phone, &packet, UDP_HEADER_SIZE, packet_dimension, addr, addrlen);
584 if(result < 0){
585 return result;
586 }
587 total_length = (size_t) result;
588 if(udp_globals.checksum_computing){
589 checksum = compute_checksum(0, packet_get_data(packet), packet_get_data_length(packet));
[21580dd]590 }else{
591 checksum = 0;
592 }
593 // prefix the udp header
[aadf01e]594 header = PACKET_PREFIX(packet, udp_header_t);
595 if(! header){
596 return udp_release_and_return(packet, ENOMEM);
[21580dd]597 }
[aadf01e]598 bzero(header, sizeof(*header));
[21580dd]599 // read the rest of the packet fragments
[aadf01e]600 for(index = 1; index < fragments; ++ index){
601 result = tl_socket_read_packet_data(udp_globals.net_phone, &next_packet, 0, packet_dimension, addr, addrlen);
602 if(result < 0){
603 return udp_release_and_return(packet, result);
[21580dd]604 }
[aadf01e]605 if(ERROR_OCCURRED(pq_add(&packet, next_packet, index, 0))){
606 return udp_release_and_return(packet, ERROR_CODE);
[1e2e0c1e]607 }
[aadf01e]608 total_length += (size_t) result;
609 if(udp_globals.checksum_computing){
610 checksum = compute_checksum(checksum, packet_get_data(next_packet), packet_get_data_length(next_packet));
[21580dd]611 }
612 }
613 // set the udp header
[aadf01e]614 header->source_port = htons((socket->port > 0) ? socket->port : 0);
615 header->destination_port = htons(dest_port);
616 header->total_length = htons(total_length + sizeof(*header));
[21580dd]617 header->checksum = 0;
[aadf01e]618 if(udp_globals.checksum_computing){
[2e99277]619 // update the pseudo header
[aadf01e]620 if(ERROR_OCCURRED(ip_client_set_pseudo_header_data_length(ip_header, headerlen, total_length + UDP_HEADER_SIZE))){
621 free(ip_header);
622 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]623 }
[2e99277]624 // finish the checksum computation
[aadf01e]625 checksum = compute_checksum(checksum, ip_header, headerlen);
626 checksum = compute_checksum(checksum, (uint8_t *) header, sizeof(*header));
627 header->checksum = htons(flip_checksum(compact_checksum(checksum)));
628 free(ip_header);
[21580dd]629 }else{
[ede63e4]630 device_id = DEVICE_INVALID_ID;
[21580dd]631 }
632 // prepare the first packet fragment
[aadf01e]633 if(ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0))){
634 return udp_release_and_return(packet, ERROR_CODE);
[21580dd]635 }
636 // send the packet
[aadf01e]637 fibril_rwlock_write_unlock(&udp_globals.lock);
638 ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0);
[21580dd]639 return EOK;
640}
641
[aadf01e]642int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen){
[21580dd]643 ERROR_DECLARE;
644
[aadf01e]645 socket_core_ref socket;
646 int packet_id;
647 packet_t packet;
648 udp_header_ref header;
649 struct sockaddr * addr;
650 size_t length;
651 uint8_t * data;
652 int result;
[21580dd]653
654 // find the socket
[aadf01e]655 socket = socket_cores_find(local_sockets, socket_id);
656 if(! socket){
657 return ENOTSOCK;
658 }
[21580dd]659 // get the next received packet
[aadf01e]660 packet_id = dyn_fifo_value(&socket->received);
661 if(packet_id < 0){
662 return NO_DATA;
663 }
664 ERROR_PROPAGATE(packet_translate(udp_globals.net_phone, &packet, packet_id));
[21580dd]665 // get udp header
[aadf01e]666 data = packet_get_data(packet);
667 if(! data){
668 pq_release(udp_globals.net_phone, packet_id);
[21580dd]669 return NO_DATA;
670 }
[aadf01e]671 header = (udp_header_ref) data;
[21580dd]672
673 // set the source address port
[aadf01e]674 result = packet_get_addr(packet, (uint8_t **) &addr, NULL);
675 if(ERROR_OCCURRED(tl_set_address_port(addr, result, ntohs(header->source_port)))){
676 pq_release(udp_globals.net_phone, packet_id);
[21580dd]677 return ERROR_CODE;
678 }
[aadf01e]679 *addrlen = (size_t) result;
[21580dd]680 // send the source address
[aadf01e]681 ERROR_PROPAGATE(data_reply(addr, * addrlen));
[21580dd]682
683 // trim the header
[aadf01e]684 ERROR_PROPAGATE(packet_trim(packet, UDP_HEADER_SIZE, 0));
[21580dd]685
686 // reply the packets
[aadf01e]687 ERROR_PROPAGATE(socket_reply_packets(packet, &length));
[21580dd]688
689 // release the packet
[aadf01e]690 dyn_fifo_pop(&socket->received);
691 pq_release(udp_globals.net_phone, packet_get_id(packet));
[21580dd]692 // return the total length
[aadf01e]693 return (int) length;
[21580dd]694}
695
[aadf01e]696int udp_release_and_return(packet_t packet, int result){
697 pq_release(udp_globals.net_phone, packet_get_id(packet));
[21580dd]698 return result;
699}
700
[849ed54]701#ifdef CONFIG_NETWORKING_modular
702
703#include <tl_standalone.h>
704
705/** Default thread for new connections.
706 *
707 * @param[in] iid The initial message identifier.
708 * @param[in] icall The initial message call structure.
709 *
710 */
711static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
712{
713 /*
714 * Accept the connection
715 * - Answer the first IPC_M_CONNECT_ME_TO call.
716 */
717 ipc_answer_0(iid, EOK);
718
719 while(true) {
720 ipc_call_t answer;
721 int answer_count;
722
723 /* Clear the answer structure */
724 refresh_answer(&answer, &answer_count);
725
726 /* Fetch the next message */
727 ipc_call_t call;
728 ipc_callid_t callid = async_get_call(&call);
729
730 /* Process the message */
731 int res = tl_module_message(callid, &call, &answer, &answer_count);
732
733 /* End if said to either by the message or the processing result */
734 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
735 return;
736
737 /* Answer the message */
738 answer_call(callid, res, &answer, answer_count);
739 }
740}
741
742/** Starts the module.
743 *
744 * @param argc The count of the command line arguments. Ignored parameter.
745 * @param argv The command line parameters. Ignored parameter.
746 *
747 * @returns EOK on success.
748 * @returns Other error codes as defined for each specific module start function.
749 *
750 */
751int main(int argc, char *argv[])
752{
753 ERROR_DECLARE;
754
755 /* Print the module label */
756 printf("Task %d - %s\n", task_get_id(), NAME);
757
758 /* Start the module */
759 if (ERROR_OCCURRED(tl_module_start(tl_client_connection))) {
760 printf(" - ERROR %i\n", ERROR_CODE);
761 return ERROR_CODE;
762 }
763
764 return EOK;
765}
766
767#endif /* CONFIG_NETWORKING_modular */
768
[21580dd]769/** @}
770 */
Note: See TracBrowser for help on using the repository browser.