Subversion Repositories HelenOS

Rev

Rev 4701 | Rev 4708 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4701 Rev 4707
Line 36... Line 36...
36
 */
36
 */
37
 
37
 
38
#include <async.h>
38
#include <async.h>
39
#include <fibril_sync.h>
39
#include <fibril_sync.h>
40
#include <malloc.h>
40
#include <malloc.h>
41
#include <stdio.h>
-
 
42
 
41
 
43
#include <ipc/ipc.h>
42
#include <ipc/ipc.h>
44
#include <ipc/services.h>
43
#include <ipc/services.h>
45
 
44
 
46
#include "../../err.h"
45
#include "../../err.h"
Line 53... Line 52...
53
#include "../../include/in.h"
52
#include "../../include/in.h"
54
#include "../../include/inet.h"
53
#include "../../include/inet.h"
55
#include "../../include/ip_client.h"
54
#include "../../include/ip_client.h"
56
#include "../../include/ip_interface.h"
55
#include "../../include/ip_interface.h"
57
#include "../../include/ip_protocols.h"
56
#include "../../include/ip_protocols.h"
-
 
57
#include "../../include/icmp_client.h"
-
 
58
#include "../../include/icmp_interface.h"
58
#include "../../include/socket.h"
59
#include "../../include/socket.h"
59
#include "../../include/socket_errno.h"
60
#include "../../include/socket_errno.h"
60
 
61
 
61
#include "../../socket/socket_core.h"
62
#include "../../socket/socket_core.h"
62
#include "../../socket/socket_messages.h"
63
#include "../../socket/socket_messages.h"
Line 77... Line 78...
77
 
78
 
78
/** Free ports pool end.
79
/** Free ports pool end.
79
 */
80
 */
80
#define UDP_FREE_PORTS_END      65535
81
#define UDP_FREE_PORTS_END      65535
81
 
82
 
82
/** Processes the received UDP packet.
83
/** Processes the received UDP packet queue.
83
 *  Is used as an entry point from the underlying IP module.
84
 *  Is used as an entry point from the underlying IP module.
-
 
85
 *  Notifies the destination socket application.
84
 *  Releases the packet on error.
86
 *  Releases the packet on error or send an ICMP error notification..
85
 *  @param device_id The device identifier. Ignored parameter.
87
 *  @param device_id The device identifier. Ignored parameter.
86
 *  @param packet The received packet. Input/output parameter.
88
 *  @param packet The received packet queue. Input/output parameter.
87
 *  @param receiver The target service. Ignored parameter.
89
 *  @param receiver The target service. Ignored parameter.
88
 *  @returns EOK on success.
-
 
89
 *  @returns Other error codes as defined for the udp_process_packet() function.
-
 
90
 */
-
 
91
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver );
-
 
92
 
-
 
93
/** Processes the received UDP packet.
-
 
94
 *  Notifies the destination socket application.
-
 
95
 *  @param packet The received packet. Input/output parameter.
90
 *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
96
 *  @returns EOK on success.
91
 *  @returns EOK on success.
97
 *  @returns EINVAL if the packet is not valid.
92
 *  @returns EINVAL if the packet is not valid.
98
 *  @returns EINVAL if the stored packet address is not the an_addr_t.
93
 *  @returns EINVAL if the stored packet address is not the an_addr_t.
99
 *  @returns EINVAL if the packet does not contain any data.
94
 *  @returns EINVAL if the packet does not contain any data.
100
 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
95
 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
101
 *  @returns ENOMEM if there is not enough memory left.
96
 *  @returns ENOMEM if there is not enough memory left.
102
 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
97
 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
103
 *  @returns Other error codes as defined for the ip_client_process_packet() function.
98
 *  @returns Other error codes as defined for the ip_client_process_packet() function.
104
 */
99
 */
-
 
100
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
-
 
101
 
-
 
102
/** Releases the packet and returns the result.
-
 
103
 *  @param packet The packet queue to be released. Input parameter.
-
 
104
 *  @param result The result to be returned. Input parameter.
-
 
105
 *  @return The result parameter.
-
 
106
 */
105
int udp_process_packet( packet_t packet );
107
static int  release_and_return( packet_t packet, int result );
-
 
108
 
-
 
109
/** Sends the port unreachable ICMP notification.
-
 
110
 *  Sends the first packet and releases all the others.
-
 
111
 *  Releases the packet queu on error.
-
 
112
 *  @param packet The packet to be send. Input parameter.
-
 
113
 *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
-
 
114
 */
-
 
115
void    udp_send_icmp_port_unreachable( packet_t packet, services_t error );
106
 
116
 
107
/** @name Socket messages processing functions
117
/** @name Socket messages processing functions
108
 */
118
 */
109
/*@{*/
119
/*@{*/
110
 
120
 
Line 194... Line 204...
194
int udp_initialize( async_client_conn_t client_connection ){
204
int udp_initialize( async_client_conn_t client_connection ){
195
    ERROR_DECLARE;
205
    ERROR_DECLARE;
196
 
206
 
197
    fibril_rwlock_initialize( & udp_globals.lock );
207
    fibril_rwlock_initialize( & udp_globals.lock );
198
    fibril_rwlock_write_lock( & udp_globals.lock );
208
    fibril_rwlock_write_lock( & udp_globals.lock );
-
 
209
    udp_globals.icmp_phone = icmp_connect_module( SERVICE_ICMP );
-
 
210
    if( udp_globals.icmp_phone < 0 ){
-
 
211
        return udp_globals.icmp_phone;
-
 
212
    }
199
    udp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg );
213
    udp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg );
200
    if( udp_globals.ip_phone < 0 ){
214
    if( udp_globals.ip_phone < 0 ){
201
        return udp_globals.ip_phone;
215
        return udp_globals.ip_phone;
202
    }
216
    }
203
    ERROR_PROPAGATE( ip_packet_size_req( udp_globals.ip_phone, -1, & udp_globals.addr_len, & udp_globals.prefix, & udp_globals.content, & udp_globals.suffix ));
217
    ERROR_PROPAGATE( ip_packet_size_req( udp_globals.ip_phone, -1, & udp_globals.addr_len, & udp_globals.prefix, & udp_globals.content, & udp_globals.suffix ));
Line 207... Line 221...
207
    udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
221
    udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
208
    fibril_rwlock_write_unlock( & udp_globals.lock );
222
    fibril_rwlock_write_unlock( & udp_globals.lock );
209
    return EOK;
223
    return EOK;
210
}
224
}
211
 
225
 
212
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver ){
226
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
213
    ERROR_DECLARE;
227
    ERROR_DECLARE;
214
 
228
 
215
    if( ERROR_OCCURRED( udp_process_packet( packet ))){
-
 
216
        pq_release( udp_globals.net_phone, packet_get_id( packet ));
-
 
217
        return ERROR_CODE;
-
 
218
    }
-
 
219
 
-
 
220
    return EOK;
-
 
221
}
-
 
222
 
-
 
223
int udp_process_packet( packet_t packet ){
-
 
224
    ERROR_DECLARE;
-
 
225
 
-
 
226
    uint8_t *       src;
-
 
227
    uint8_t *       dest;
-
 
228
    int             length;
229
    int             length;
-
 
230
    int             offset;
229
    void *          data;
231
    uint8_t *       data;
230
    udp_header_ref  header;
232
    udp_header_ref  header;
231
    socket_core_ref *   socket;
233
    socket_core_ref *   socket;
232
    packet_t        next_packet;
234
    packet_t        next_packet;
233
    int             total_length;
235
    int             total_length;
234
//  uint16_t        checksum;
236
//  uint16_t        checksum;
235
    int             fragments;
237
    int             fragments;
236
    packet_t        tmp_packet;
238
    packet_t        tmp_packet;
-
 
239
    icmp_type_t     type;
-
 
240
    icmp_code_t     code;
237
 
241
 
-
 
242
    if( error ){
-
 
243
        switch( error ){
-
 
244
            case SERVICE_ICMP:
238
    // get packet data
245
                // process error
-
 
246
                // TODO remove debug dump
-
 
247
                // length = icmp_client_header_length( packet );
239
    length = packet_get_addr( packet, & src, & dest );
248
                length = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
-
 
249
                if( length < 0 ){
240
    if( length != sizeof( in_addr_t )) return EINVAL;
250
                    return release_and_return( packet, length );
-
 
251
                }
-
 
252
                printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) );
-
 
253
                if( ERROR_OCCURRED( packet_trim( packet, length, 0 ))){
-
 
254
                    return release_and_return( packet, ERROR_CODE );
-
 
255
                }
-
 
256
                break;
-
 
257
            default:
-
 
258
                return release_and_return( packet, ENOTSUP );
-
 
259
        }
-
 
260
    }
241
    // TODO process received ipopts?
261
    // TODO process received ipopts?
242
    ERROR_PROPAGATE( ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL ));
262
    offset = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL );
-
 
263
    if( offset < 0 ){
-
 
264
        return release_and_return( packet, offset );
-
 
265
    }
243
 
266
 
244
    length = packet_get_data_length( packet );
267
    length = packet_get_data_length( packet );
245
    if( length <= 0 ) return EINVAL;
268
    if( length <= 0 ){
-
 
269
        return release_and_return( packet, EINVAL );
-
 
270
    }
246
    if( length < sizeof( udp_header_t )) return NO_DATA;
271
    if( length < sizeof( udp_header_t ) + offset ){
-
 
272
        return release_and_return( packet, NO_DATA );
-
 
273
    }
247
    data = packet_get_data( packet );
274
    data = packet_get_data( packet );
248
    if( ! data ) return NO_DATA;
275
    if( ! data ){
-
 
276
        return release_and_return( packet, NO_DATA );
-
 
277
    }
249
    // get udp header
278
    // get udp header
250
    header = ( udp_header_ref ) data;
279
    header = ( udp_header_ref )( data + offset );
251
    // find the destination socket
280
    // find the destination socket
252
    socket = socket_ports_find( & udp_globals.sockets, ntohs( header->dest ));
281
    socket = socket_ports_find( & udp_globals.sockets, ntohs( header->dest ));
-
 
282
    if( ! socket ){
-
 
283
        udp_send_icmp_port_unreachable( packet, error );
253
    if( ! socket ) return EADDRNOTAVAIL;
284
        return EADDRNOTAVAIL;
-
 
285
    }
-
 
286
    // trim after successful processing to be able to send an ICMP error message!
-
 
287
    ERROR_PROPAGATE( packet_trim( packet, offset, 0 ));
254
    // count the received packet fragments
288
    // count the received packet fragments
255
    next_packet = packet;
289
    next_packet = packet;
256
    fragments = 0;
290
    fragments = 0;
257
    total_length = ntohs( header->len );
291
    total_length = ntohs( header->len );
258
    do{
292
    do{
259
        ++ fragments;
293
        ++ fragments;
260
        length = packet_get_data_length( packet );
294
        length = packet_get_data_length( packet );
261
        if( ! length ) return NO_DATA;
295
        if( ! length ){
-
 
296
            return release_and_return( packet, NO_DATA );
-
 
297
        }
262
        if( total_length < length ){
298
        if( total_length < length ){
263
            // cut of the suffix if too long
299
            // cut of the suffix if too long
264
            ERROR_PROPAGATE( packet_trim( next_packet, 0, length - total_length ));
300
            if( ERROR_OCCURRED( packet_trim( next_packet, 0, length - total_length ))){
-
 
301
                return release_and_return( packet, ERROR_CODE );
-
 
302
            }
265
            // relese the rest of the packet fragments
303
            // relese the rest of the packet fragments
266
            tmp_packet = pq_next( next_packet );
304
            tmp_packet = pq_next( next_packet );
267
            while( tmp_packet ){
305
            while( tmp_packet ){
268
                next_packet = pq_detach( tmp_packet );
306
                next_packet = pq_detach( tmp_packet );
269
                pq_release( udp_globals.net_phone, packet_get_id( tmp_packet ));
307
                pq_release( udp_globals.net_phone, packet_get_id( tmp_packet ));
Line 275... Line 313...
275
    /*  if( header->header_checksum ){
313
    /*  if( header->header_checksum ){
276
        }
314
        }
277
    */
315
    */
278
    }while(( next_packet = pq_next( next_packet )) && ( total_length > 0 ));
316
    }while(( next_packet = pq_next( next_packet )) && ( total_length > 0 ));
279
    // queue the received packet
317
    // queue the received packet
280
    ERROR_PROPAGATE( dyn_fifo_push( &( ** socket ).received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ));
318
    if( ERROR_OCCURRED( dyn_fifo_push( &( ** socket ).received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ))){
-
 
319
        return release_and_return( packet, ERROR_CODE );
-
 
320
    }
281
 
321
 
282
    // notify the destination socket
322
    // notify the destination socket
283
    async_msg_2(( ** socket ).phone, NET_SOCKET_RECEIVED, ( ** socket ).socket_id, fragments );
323
    async_msg_2(( ** socket ).phone, NET_SOCKET_RECEIVED, ( ** socket ).socket_id, fragments );
284
    return EOK;
324
    return EOK;
285
}
325
}
Line 292... Line 332...
292
    * answer_count = 0;
332
    * answer_count = 0;
293
    switch( IPC_GET_METHOD( * call )){
333
    switch( IPC_GET_METHOD( * call )){
294
        case NET_TL_RECEIVED:
334
        case NET_TL_RECEIVED:
295
            fibril_rwlock_read_lock( & udp_globals.lock );
335
            fibril_rwlock_read_lock( & udp_globals.lock );
296
            if( ! ERROR_OCCURRED( packet_translate( udp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
336
            if( ! ERROR_OCCURRED( packet_translate( udp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
297
                ERROR_CODE = udp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_UDP );
337
                ERROR_CODE = udp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_UDP, IPC_GET_ERROR( call ));
298
            }
338
            }
299
            fibril_rwlock_read_unlock( & udp_globals.lock );
339
            fibril_rwlock_read_unlock( & udp_globals.lock );
300
            return ERROR_CODE;
340
            return ERROR_CODE;
301
        case IPC_M_CONNECT_TO_ME:
341
        case IPC_M_CONNECT_TO_ME:
302
            return process_client_messages( callid, * call );
342
            return process_client_messages( callid, * call );
Line 493... Line 533...
493
            if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_UDP, 0, 0, 0, 0 ))){
533
            if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_UDP, 0, 0, 0, 0 ))){
494
                pq_release( udp_globals.net_phone, packet_get_id( packet ));
534
                pq_release( udp_globals.net_phone, packet_get_id( packet ));
495
                return ERROR_CODE;
535
                return ERROR_CODE;
496
            }
536
            }
497
            // send the packet
537
            // send the packet
498
            return ip_send_msg( udp_globals.ip_phone, socket->device_id, packet, SERVICE_UDP );
538
            return ip_send_msg( udp_globals.ip_phone, socket->device_id, packet, SERVICE_UDP, 0 );
499
        // TODO IPv6
539
        // TODO IPv6
500
        default:
540
        default:
501
            return EAFNOSUPPORT;
541
            return EAFNOSUPPORT;
502
    }
542
    }
503
    return EOK;
543
    return EOK;
Line 643... Line 683...
643
        return ERROR_CODE;
683
        return ERROR_CODE;
644
    }
684
    }
645
    return length;
685
    return length;
646
}
686
}
647
 
687
 
-
 
688
static int  release_and_return( packet_t packet, int result ){
-
 
689
    pq_release( udp_globals.net_phone, packet_get_id( packet ));
-
 
690
    return result;
-
 
691
}
-
 
692
 
-
 
693
void udp_send_icmp_port_unreachable( packet_t packet, services_t error ){
-
 
694
    packet_t    next;
-
 
695
    uint8_t *   src;
-
 
696
    int         length;
-
 
697
 
-
 
698
    // detach the first packet and release the others
-
 
699
    next = pq_detach( packet );
-
 
700
    if( next ){
-
 
701
        pq_release( udp_globals.net_phone, packet_get_id( next ));
-
 
702
    }
-
 
703
    length = packet_get_addr( packet, & src, NULL );
-
 
704
    if(( length > 0 )
-
 
705
    && ( ! error )
-
 
706
    && ( udp_globals.icmp_phone >= 0 )
-
 
707
    // set both addresses to the source one (avoids the source address deletion before setting the destination one)
-
 
708
    && ( packet_set_addr( packet, src, src, length ) == EOK )){
-
 
709
        icmp_destination_unreachable_msg( udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet );
-
 
710
    }else{
-
 
711
        return release_and_return( packet, EINVAL );
-
 
712
    }
-
 
713
}
-
 
714
 
648
/** @}
715
/** @}
649
 */
716
 */