source: mainline/uspace/srv/net/nil/eth/eth.c@ f1848d6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1848d6 was 21580dd, checked in by Lukas Mejdrech <lukas@…>, 16 years ago

Merged with network branch svn://svn.helenos.org/HelenOS/branches/network revision 4759; ipc_share_* and ipc_data_* changed to async_*; client connection in module.c returns on IPC_M_PHONE_HUNGUP; * Qemu scripts renamed to net-qe.*; (the dp8390 does not respond)

  • Property mode set to 100644
File size: 25.1 KB
Line 
1/*
2 * Copyright (c) 2009 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 eth
30 * @{
31 */
32
33/** @file
34 * Ethernet module implementation.
35 * @see eth.h
36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <stdio.h>
42#include <string.h>
43
44#include <ipc/ipc.h>
45#include <ipc/services.h>
46
47#include "../../err.h"
48#include "../../messages.h"
49#include "../../modules.h"
50
51#include "../../include/byteorder.h"
52#include "../../include/checksum.h"
53#include "../../include/ethernet_lsap.h"
54#include "../../include/ethernet_protocols.h"
55#include "../../include/protocol_map.h"
56#include "../../include/device.h"
57#include "../../include/netif_interface.h"
58#include "../../include/net_interface.h"
59#include "../../include/nil_interface.h"
60#include "../../include/il_interface.h"
61
62#include "../../structures/measured_strings.h"
63#include "../../structures/packet/packet_client.h"
64
65#include "../nil_module.h"
66
67#include "eth.h"
68#include "eth_header.h"
69
70/** Reserved packet prefix length.
71 */
72#define ETH_PREFIX ( sizeof( eth_header_t ) + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ))
73
74/** Reserved packet suffix length.
75 */
76#define ETH_SUFFIX sizeof( eth_fcs_t )
77
78/** Maximum packet content length.
79 */
80#define ETH_MAX_CONTENT 1500u
81
82/** Minimum packet content length.
83 */
84#define ETH_MIN_CONTENT 46u
85
86/** Maximum tagged packet content length.
87 */
88#define ETH_MAX_TAGGED_CONTENT( flags ) ( ETH_MAX_CONTENT - (( IS_8023_2_LSAP( flags ) || IS_8023_2_SNAP( flags )) ? sizeof( eth_header_lsap_t ) : 0 ) - ( IS_8023_2_SNAP( flags ) ? sizeof( eth_header_snap_t ) : 0 ))
89
90/** Minimum tagged packet content length.
91 */
92#define ETH_MIN_TAGGED_CONTENT( flags ) ( ETH_MIN_CONTENT - (( IS_8023_2_LSAP( flags ) || IS_8023_2_SNAP( flags )) ? sizeof( eth_header_lsap_t ) : 0 ) - ( IS_8023_2_SNAP( flags ) ? sizeof( eth_header_snap_t ) : 0 ))
93
94/** Dummy flag shift value.
95 */
96#define ETH_DUMMY_SHIFT 0
97
98/** Mode flag shift value.
99 */
100#define ETH_MODE_SHIFT 1
101
102/** Dummy device flag.
103 * Preamble and FCS are mandatory part of the packets.
104 */
105#define ETH_DUMMY ( 1 << ETH_DUMMY_SHIFT )
106
107/** Returns the dummy flag.
108 * @see ETH_DUMMY
109 */
110#define IS_DUMMY( flags ) (( flags ) & ETH_DUMMY )
111
112/** Device mode flags.
113 * @see ETH_DIX
114 * @see ETH_8023_2_LSAP
115 * @see ETH_8023_2_SNAP
116 */
117#define ETH_MODE_MASK ( 3 << ETH_MODE_SHIFT )
118
119/** DIX Ethernet mode flag.
120 */
121#define ETH_DIX ( 1 << ETH_MODE_SHIFT )
122
123/** Returns whether the DIX Ethernet mode flag is set.
124 * @param[in] flags The ethernet flags.
125 * @see ETH_DIX
126 */
127#define IS_DIX( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_DIX )
128
129/** 802.3 + 802.2 + LSAP mode flag.
130 */
131#define ETH_8023_2_LSAP ( 2 << ETH_MODE_SHIFT )
132
133/** Returns whether the 802.3 + 802.2 + LSAP mode flag is set.
134 * @param[in] flags The ethernet flags.
135 * @see ETH_8023_2_LSAP
136 */
137#define IS_8023_2_LSAP( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_8023_2_LSAP )
138
139/** 802.3 + 802.2 + LSAP + SNAP mode flag.
140 */
141#define ETH_8023_2_SNAP ( 3 << ETH_MODE_SHIFT )
142
143/** Returns whether the 802.3 + 802.2 + LSAP + SNAP mode flag is set.
144 * @param[in] flags The ethernet flags.
145 * @see ETH_8023_2_SNAP
146 */
147#define IS_8023_2_SNAP( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_8023_2_SNAP )
148
149/** Type definition of the ethernet address type.
150 * @see eth_addr_type
151 */
152typedef enum eth_addr_type eth_addr_type_t;
153
154/** Type definition of the ethernet address type pointer.
155 * @see eth_addr_type
156 */
157typedef eth_addr_type_t * eth_addr_type_ref;
158
159/** Ethernet address type.
160 */
161enum eth_addr_type{
162 /** Local address.
163 */
164 ETH_LOCAL_ADDR,
165 /** Broadcast address.
166 */
167 ETH_BROADCAST_ADDR
168};
169
170/** Ethernet module global data.
171 */
172eth_globals_t eth_globals;
173
174/** @name Message processing functions
175 */
176/*@{*/
177
178/** Processes IPC messages from the registered device driver modules in an infinite loop.
179 * @param[in] iid The message identifier.
180 * @param[in,out] icall The message parameters.
181 */
182void eth_receiver( ipc_callid_t iid, ipc_call_t * icall );
183
184/** Registers new device or updates the MTU of an existing one.
185 * Determines the device local hardware address.
186 * @param[in] device_id The new device identifier.
187 * @param[in] service The device driver service.
188 * @param[in] mtu The device maximum transmission unit.
189 * @returns EOK on success.
190 * @returns EEXIST if the device with the different service exists.
191 * @returns ENOMEM if there is not enough memory left.
192 * @returns Other error codes as defined for the net_get_device_conf_req() function.
193 * @returns Other error codes as defined for the netif_bind_service() function.
194 * @returns Other error codes as defined for the netif_get_addr_req() function.
195 */
196int eth_device_message( device_id_t device_id, services_t service, size_t mtu );
197
198/** Registers receiving module service.
199 * Passes received packets for this service.
200 * @param[in] service The module service.
201 * @param[in] phone The service phone.
202 * @returns EOK on success.
203 * @returns ENOENT if the service is not known.
204 * @returns ENOMEM if there is not enough memory left.
205 */
206int eth_register_message( services_t service, int phone );
207
208/** Returns the device packet dimensions for sending.
209 * @param[in] device_id The device identifier.
210 * @param[out] addr_len The minimum reserved address length.
211 * @param[out] prefix The minimum reserved prefix size.
212 * @param[out] content The maximum content size.
213 * @param[out] suffix The minimum reserved suffix size.
214 * @returns EOK on success.
215 * @returns EBADMEM if either one of the parameters is NULL.
216 * @returns ENOENT if there is no such device.
217 */
218int eth_packet_space_message( device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix );
219
220/** Returns the device hardware address.
221 * @param[in] device_id The device identifier.
222 * @param[in] type Type of the desired address.
223 * @param[out] address The device hardware address.
224 * @returns EOK on success.
225 * @returns EBADMEM if the address parameter is NULL.
226 * @returns ENOENT if there no such device.
227 */
228int eth_addr_message( device_id_t device_id, eth_addr_type_t type, measured_string_ref * address );
229
230/** Sends the packet queue.
231 * Sends only packet successfully processed by the eth_prepare_packet() function.
232 * @param[in] device_id The device identifier.
233 * @param[in] packet The packet queue.
234 * @param[in] sender The sending module service.
235 * @returns EOK on success.
236 * @returns ENOENT if there no such device.
237 * @returns EINVAL if the service parameter is not known.
238 */
239int eth_send_message( device_id_t device_id, packet_t packet, services_t sender );
240
241/*@}*/
242
243/** Processes the received packet and chooses the target registered module.
244 * @param[in] flags The device flags.
245 * @param[in] packet The packet.
246 * @returns The target registered module.
247 * @returns NULL if the packet is not long enough.
248 * @returns NULL if the packet is too long.
249 * @returns NULL if the raw ethernet protocol is used.
250 * @returns NULL if the dummy device FCS checksum is invalid.
251 * @returns NULL if the packet address length is not big enough.
252 */
253eth_proto_ref eth_process_packet( int flags, packet_t packet );
254
255/** Prepares the packet for sending.
256 * @param[in] flags The device flags.
257 * @param[in] packet The packet.
258 * @param[in] src_addr The source hardware address.
259 * @param[in] ethertype The ethernet protocol type.
260 * @param[in] mtu The device maximum transmission unit.
261 * @returns EOK on success.
262 * @returns EINVAL if the packet addresses length is not long enough.
263 * @returns EINVAL if the packet is bigger than the device MTU.
264 * @returns ENOMEM if there is not enough memory in the packet.
265 */
266int eth_prepare_packet( int flags, packet_t packet, uint8_t * src_addr, int ethertype, size_t mtu );
267
268DEVICE_MAP_IMPLEMENT( eth_devices, eth_device_t )
269
270INT_MAP_IMPLEMENT( eth_protos, eth_proto_t )
271
272int nil_device_state_msg( int nil_phone, device_id_t device_id, int state ){
273 int index;
274 eth_proto_ref proto;
275
276 fibril_rwlock_read_lock( & eth_globals.protos_lock );
277 for( index = eth_protos_count( & eth_globals.protos ) - 1; index >= 0; -- index ){
278 proto = eth_protos_get_index( & eth_globals.protos, index );
279 if( proto && proto->phone ) il_device_state_msg( proto->phone, device_id, state, proto->service );
280 }
281 fibril_rwlock_read_unlock( & eth_globals.protos_lock );
282 return EOK;
283}
284
285int nil_initialize( int net_phone ){
286 ERROR_DECLARE;
287
288 fibril_rwlock_initialize( & eth_globals.devices_lock );
289 fibril_rwlock_initialize( & eth_globals.protos_lock );
290 fibril_rwlock_write_lock( & eth_globals.devices_lock );
291 fibril_rwlock_write_lock( & eth_globals.protos_lock );
292 eth_globals.net_phone = net_phone;
293 eth_globals.broadcast_addr = measured_string_create_bulk( "\xFF\xFF\xFF\xFF\xFF\xFF", CONVERT_SIZE( uint8_t, char, ETH_ADDR ));
294 if( ! eth_globals.broadcast_addr ) return ENOMEM;
295 ERROR_PROPAGATE( eth_devices_initialize( & eth_globals.devices ));
296 if( ERROR_OCCURRED( eth_protos_initialize( & eth_globals.protos ))){
297 eth_devices_destroy( & eth_globals.devices );
298 return ERROR_CODE;
299 }
300 fibril_rwlock_write_unlock( & eth_globals.protos_lock );
301 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
302 return EOK;
303}
304
305int eth_device_message( device_id_t device_id, services_t service, size_t mtu ){
306 ERROR_DECLARE;
307
308 eth_device_ref device;
309 int index;
310 measured_string_t names[ 2 ] = {{ "ETH_MODE", 8 }, { "ETH_DUMMY", 9 }};
311 measured_string_ref configuration;
312 size_t count = sizeof( names ) / sizeof( measured_string_t );
313 char * data;
314 eth_proto_ref proto;
315
316 fibril_rwlock_write_lock( & eth_globals.devices_lock );
317 // an existing device?
318 device = eth_devices_find( & eth_globals.devices, device_id );
319 if( device ){
320 if( device->service != service ){
321 printf( "Device %d already exists\n", device->device_id );
322 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
323 return EEXIST;
324 }else{
325 // update mtu
326 if(( mtu > 0 ) && ( mtu <= ETH_MAX_TAGGED_CONTENT( device->flags ))){
327 device->mtu = mtu;
328 }else{
329 device->mtu = ETH_MAX_TAGGED_CONTENT( device->flags );
330 }
331 printf( "Device %d already exists:\tMTU\t= %d\n", device->device_id, device->mtu );
332 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
333 // notify all upper layer modules
334 fibril_rwlock_read_lock( & eth_globals.protos_lock );
335 for( index = 0; index < eth_protos_count( & eth_globals.protos ); ++ index ){
336 proto = eth_protos_get_index( & eth_globals.protos, index );
337 if ( proto->phone ){
338 il_mtu_changed_msg( proto->phone, device->device_id, device->mtu, proto->service );
339 }
340 }
341 fibril_rwlock_read_unlock( & eth_globals.protos_lock );
342 return EOK;
343 }
344 }else{
345 // create a new device
346 device = ( eth_device_ref ) malloc( sizeof( eth_device_t ));
347 if( ! device ) return ENOMEM;
348 device->device_id = device_id;
349 device->service = service;
350 device->flags = 0;
351 if(( mtu > 0 ) && ( mtu <= ETH_MAX_TAGGED_CONTENT( device->flags ))){
352 device->mtu = mtu;
353 }else{
354 device->mtu = ETH_MAX_TAGGED_CONTENT( device->flags );
355 }
356 configuration = & names[ 0 ];
357 if( ERROR_OCCURRED( net_get_device_conf_req( eth_globals.net_phone, device->device_id, & configuration, count, & data ))){
358 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
359 free( device );
360 return ERROR_CODE;
361 }
362 if( configuration ){
363 if( ! str_lcmp( configuration[ 0 ].value, "DIX", configuration[ 0 ].length )){
364 device->flags |= ETH_DIX;
365 }else if( ! str_lcmp( configuration[ 0 ].value, "8023_2_LSAP", configuration[ 0 ].length )){
366 device->flags |= ETH_8023_2_LSAP;
367 }else device->flags |= ETH_8023_2_SNAP;
368 if(( configuration[ 1 ].value ) && ( configuration[ 1 ].value[ 0 ] == 'y' )){
369 device->flags |= ETH_DUMMY;
370 }
371 net_free_settings( configuration, data );
372 }else{
373 device->flags |= ETH_8023_2_SNAP;
374 }
375 // bind the device driver
376 device->phone = netif_bind_service( device->service, device->device_id, SERVICE_ETHERNET, eth_receiver );
377 if( device->phone < 0 ){
378 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
379 free( device );
380 return device->phone;
381 }
382 // get hardware address
383 if( ERROR_OCCURRED( netif_get_addr_req( device->phone, device->device_id, & device->addr, & device->addr_data ))){
384 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
385 free( device );
386 return ERROR_CODE;
387 }
388 // add to the cache
389 index = eth_devices_add( & eth_globals.devices, device->device_id, device );
390 if( index < 0 ){
391 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
392 free( device->addr );
393 free( device->addr_data );
394 free( device );
395 return index;
396 }
397 printf( "New device registered:\n\tid\t= %d\n\tservice\t= %d\n\tMTU\t= %d\n\taddress\t= %X:%X:%X:%X:%X:%X\n\tflags\t= 0x%x\n", device->device_id, device->service, device->mtu, device->addr_data[ 0 ], device->addr_data[ 1 ], device->addr_data[ 2 ], device->addr_data[ 3 ], device->addr_data[ 4 ], device->addr_data[ 5 ], device->flags );
398 }
399 fibril_rwlock_write_unlock( & eth_globals.devices_lock );
400 return EOK;
401}
402
403eth_proto_ref eth_process_packet( int flags, packet_t packet ){
404 ERROR_DECLARE;
405
406 eth_header_snap_ref header;
407 size_t length;
408 eth_type_t type;
409 size_t prefix;
410 size_t suffix;
411 eth_fcs_ref fcs;
412 uint8_t * data;
413
414 length = packet_get_data_length( packet );
415 if( IS_DUMMY( flags )){
416 packet_trim( packet, sizeof( eth_preamble_t ), 0 );
417 }
418 if( length < sizeof( eth_header_t ) + ETH_MIN_CONTENT + ( IS_DUMMY( flags ) ? ETH_SUFFIX : 0 )) return NULL;
419 data = packet_get_data( packet );
420 header = ( eth_header_snap_ref ) data;
421 type = ntohs( header->header.ethertype );
422 if( type >= ETH_MIN_PROTO ){
423 // DIX Ethernet
424 prefix = sizeof( eth_header_t );
425 suffix = 0;
426 fcs = ( eth_fcs_ref ) data + length - sizeof( eth_fcs_t );
427 length -= sizeof( eth_fcs_t );
428 }else if( type <= ETH_MAX_CONTENT ){
429 // translate "LSAP" values
430 if(( header->lsap.dsap == ETH_LSAP_GLSAP ) && ( header->lsap.ssap == ETH_LSAP_GLSAP )){
431 // raw packet
432 // discard
433 return NULL;
434 }else if(( header->lsap.dsap == ETH_LSAP_SNAP ) && ( header->lsap.ssap == ETH_LSAP_SNAP )){
435 // IEEE 802.3 + 802.2 + LSAP + SNAP
436 // organization code not supported
437 type = ntohs( header->snap.ethertype );
438 prefix = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t );
439 }else{
440 // IEEE 802.3 + 802.2 LSAP
441 type = lsap_map( header->lsap.dsap );
442 prefix = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t);
443 }
444 suffix = ( type < ETH_MIN_CONTENT ) ? ETH_MIN_CONTENT - type : 0u;
445 fcs = ( eth_fcs_ref ) data + prefix + type + suffix;
446 suffix += length - prefix - type;
447 length = prefix + type + suffix;
448 }else{
449 // invalid length/type, should not occurr
450 return NULL;
451 }
452 if( IS_DUMMY( flags )){
453 if(( ~ compute_crc32( ~ 0u, data, length * 8 )) != ntohl( * fcs )){
454 return NULL;
455 }
456 suffix += sizeof( eth_fcs_t );
457 }
458 if( ERROR_OCCURRED( packet_set_addr( packet, header->header.source_address, header->header.destination_address, ETH_ADDR ))
459 || ERROR_OCCURRED( packet_trim( packet, prefix, suffix ))){
460 return NULL;
461 }
462 return eth_protos_find( & eth_globals.protos, type );
463}
464
465int nil_received_msg( int nil_phone, device_id_t device_id, packet_t packet, services_t target ){
466 eth_proto_ref proto;
467 packet_t next;
468 eth_device_ref device;
469 int flags;
470
471 fibril_rwlock_read_lock( & eth_globals.devices_lock );
472 device = eth_devices_find( & eth_globals.devices, device_id );
473 if( ! device ){
474 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
475 return ENOENT;
476 }
477 flags = device->flags;
478 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
479 fibril_rwlock_read_lock( & eth_globals.protos_lock );
480 do{
481 next = pq_detach( packet );
482 proto = eth_process_packet( flags, packet );
483 if( proto ){
484 il_received_msg( proto->phone, device_id, packet, proto->service );
485 }else{
486 // drop invalid/unknown
487 pq_release( eth_globals.net_phone, packet_get_id( packet ));
488 }
489 packet = next;
490 }while( packet );
491 fibril_rwlock_read_unlock( & eth_globals.protos_lock );
492 return EOK;
493}
494
495int eth_packet_space_message( device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix ){
496 eth_device_ref device;
497
498 if( !( addr_len && prefix && content && suffix )) return EBADMEM;
499 fibril_rwlock_read_lock( & eth_globals.devices_lock );
500 device = eth_devices_find( & eth_globals.devices, device_id );
501 if( ! device ){
502 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
503 return ENOENT;
504 }
505 * content = device->mtu;
506 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
507 * addr_len = ETH_ADDR;
508 * prefix = ETH_PREFIX;
509 * suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
510 return EOK;
511}
512
513int eth_addr_message( device_id_t device_id, eth_addr_type_t type, measured_string_ref * address ){
514 eth_device_ref device;
515
516 if( ! address ) return EBADMEM;
517 if( type == ETH_BROADCAST_ADDR ){
518 * address = eth_globals.broadcast_addr;
519 }else{
520 fibril_rwlock_read_lock( & eth_globals.devices_lock );
521 device = eth_devices_find( & eth_globals.devices, device_id );
522 if( ! device ){
523 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
524 return ENOENT;
525 }
526 * address = device->addr;
527 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
528 }
529 return ( * address ) ? EOK : ENOENT;
530}
531
532int eth_register_message( services_t service, int phone ){
533 eth_proto_ref proto;
534 int protocol;
535 int index;
536
537 protocol = protocol_map( SERVICE_ETHERNET, service );
538 if( ! protocol ) return ENOENT;
539 fibril_rwlock_write_lock( & eth_globals.protos_lock );
540 proto = eth_protos_find( & eth_globals.protos, protocol );
541 if( proto ){
542 proto->phone = phone;
543 fibril_rwlock_write_unlock( & eth_globals.protos_lock );
544 return EOK;
545 }else{
546 proto = ( eth_proto_ref ) malloc( sizeof( eth_proto_t ));
547 if( ! proto ){
548 fibril_rwlock_write_unlock( & eth_globals.protos_lock );
549 return ENOMEM;
550 }
551 proto->service = service;
552 proto->protocol = protocol;
553 proto->phone = phone;
554 index = eth_protos_add( & eth_globals.protos, protocol, proto );
555 if( index < 0 ){
556 fibril_rwlock_write_unlock( & eth_globals.protos_lock );
557 free( proto );
558 return index;
559 }
560 }
561 printf( "New protocol registered:\n\tprotocol\t= 0x%x\n\tservice\t= %d\n\tphone\t= %d\n", proto->protocol, proto->service, proto->phone );
562 fibril_rwlock_write_unlock( & eth_globals.protos_lock );
563 return EOK;
564}
565
566int eth_prepare_packet( int flags, packet_t packet, uint8_t * src_addr, int ethertype, size_t mtu ){
567 eth_header_snap_ref header;
568 eth_header_lsap_ref header_lsap;
569 eth_header_ref header_dix;
570 eth_fcs_ref fcs;
571 uint8_t * src;
572 uint8_t * dest;
573 size_t length;
574 int i;
575 void * padding;
576 eth_preamble_ref preamble;
577
578 i = packet_get_addr( packet, & src, & dest );
579 if( i < 0 ) return i;
580 if( i != ETH_ADDR ) return EINVAL;
581 length = packet_get_data_length( packet );
582 if( length > mtu ) return EINVAL;
583 if( length < ETH_MIN_TAGGED_CONTENT( flags )){
584 padding = packet_suffix( packet, ETH_MIN_TAGGED_CONTENT( flags ) - length );
585 if( ! padding ) return ENOMEM;
586 bzero( padding, ETH_MIN_TAGGED_CONTENT( flags ) - length );
587 }
588 if( IS_DUMMY( flags )){
589 preamble = PACKET_PREFIX( packet, eth_preamble_t );
590 if( ! preamble ) return ENOMEM;
591 for( i = 0; i < 7; ++ i ) preamble->preamble[ i ] = ETH_PREAMBLE;
592 preamble->sfd = ETH_SFD;
593 }
594 if( IS_DIX( flags )){
595 header_dix = PACKET_PREFIX( packet, eth_header_t );
596 if( ! header_dix ) return ENOMEM;
597 header_dix->ethertype = ( uint16_t ) ethertype;
598 memcpy( header_dix->source_address, src_addr, ETH_ADDR );
599 memcpy( header_dix->destination_address, dest, ETH_ADDR );
600 src = & header_dix->destination_address[ 0 ];
601 }else if( IS_8023_2_LSAP( flags )){
602 header_lsap = PACKET_PREFIX( packet, eth_header_lsap_t );
603 if( ! header_lsap ) return ENOMEM;
604 header_lsap->header.ethertype = htons( length + sizeof( eth_header_lsap_t ));
605 header_lsap->lsap.dsap = lsap_unmap( ntohs( ethertype ));
606 header_lsap->lsap.ssap = header_lsap->lsap.dsap;
607 header_lsap->lsap.ctrl = IEEE_8023_2_UI;
608 memcpy( header_lsap->header.source_address, src_addr, ETH_ADDR );
609 memcpy( header_lsap->header.destination_address, dest, ETH_ADDR );
610 src = & header_lsap->header.destination_address[ 0 ];
611 }else if( IS_8023_2_SNAP( flags )){
612 header = PACKET_PREFIX( packet, eth_header_snap_t );
613 if( ! header ) return ENOMEM;
614 header->header.ethertype = htons( length + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ));
615 header->lsap.dsap = ( uint16_t ) ETH_LSAP_SNAP;
616 header->lsap.ssap = header->lsap.dsap;
617 header->lsap.ctrl = IEEE_8023_2_UI;
618 for( i = 0; i < 3; ++ i ) header->snap.protocol[ i ] = 0;
619 header->snap.ethertype = ( uint16_t ) ethertype;
620 memcpy( header->header.source_address, src_addr, ETH_ADDR );
621 memcpy( header->header.destination_address, dest, ETH_ADDR );
622 src = & header->header.destination_address[ 0 ];
623 }
624 if( IS_DUMMY( flags )){
625 fcs = PACKET_SUFFIX( packet, eth_fcs_t );
626 if( ! fcs ) return ENOMEM;
627 * fcs = htonl( ~ compute_crc32( ~ 0u, src, length * 8 ));
628 }
629 return EOK;
630}
631
632int eth_send_message( device_id_t device_id, packet_t packet, services_t sender ){
633 ERROR_DECLARE;
634
635 eth_device_ref device;
636 packet_t next;
637 packet_t tmp;
638 int ethertype;
639
640 ethertype = htons( protocol_map( SERVICE_ETHERNET, sender ));
641 if( ! ethertype ){
642 pq_release( eth_globals.net_phone, packet_get_id( packet ));
643 return EINVAL;
644 }
645 fibril_rwlock_read_lock( & eth_globals.devices_lock );
646 device = eth_devices_find( & eth_globals.devices, device_id );
647 if( ! device ){
648 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
649 return ENOENT;
650 }
651 // process packet queue
652 next = packet;
653 do{
654 if( ERROR_OCCURRED( eth_prepare_packet( device->flags, next, ( uint8_t * ) device->addr->value, ethertype, device->mtu ))){
655 // release invalid packet
656 tmp = pq_detach( next );
657 if( next == packet ) packet = tmp;
658 pq_release( eth_globals.net_phone, packet_get_id( next ));
659 next = tmp;
660 }else{
661 next = pq_next( next );
662 }
663 }while( next );
664 // send packet queue
665 if( packet ){
666 netif_send_msg( device->phone, device_id, packet, SERVICE_ETHERNET );
667 }
668 fibril_rwlock_read_unlock( & eth_globals.devices_lock );
669 return EOK;
670}
671
672int nil_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
673 ERROR_DECLARE;
674
675 measured_string_ref address;
676 packet_t packet;
677
678// printf( "message %d - %d\n", IPC_GET_METHOD( * call ), NET_NIL_FIRST );
679 * answer_count = 0;
680 switch( IPC_GET_METHOD( * call )){
681 case IPC_M_PHONE_HUNGUP:
682 return EOK;
683 case NET_NIL_DEVICE:
684 return eth_device_message( IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), IPC_GET_MTU( call ));
685 case NET_NIL_SEND:
686 ERROR_PROPAGATE( packet_translate( eth_globals.net_phone, & packet, IPC_GET_PACKET( call )));
687 return eth_send_message( IPC_GET_DEVICE( call ), packet, IPC_GET_SERVICE( call ));
688 case NET_NIL_PACKET_SPACE:
689 ERROR_PROPAGATE( eth_packet_space_message( IPC_GET_DEVICE( call ), IPC_SET_ADDR( answer ), IPC_SET_PREFIX( answer ), IPC_SET_CONTENT( answer ), IPC_SET_SUFFIX( answer )));
690 * answer_count = 4;
691 return EOK;
692 case NET_NIL_ADDR:
693 ERROR_PROPAGATE( eth_addr_message( IPC_GET_DEVICE( call ), ETH_LOCAL_ADDR, & address ));
694 return measured_strings_reply( address, 1 );
695 case NET_NIL_BROADCAST_ADDR:
696 ERROR_PROPAGATE( eth_addr_message( IPC_GET_DEVICE( call ), ETH_BROADCAST_ADDR, & address ));
697 return measured_strings_reply( address, 1 );
698 case IPC_M_CONNECT_TO_ME:
699 return eth_register_message( NIL_GET_PROTO( call ), IPC_GET_PHONE( call ));
700 }
701 return ENOTSUP;
702}
703
704void eth_receiver( ipc_callid_t iid, ipc_call_t * icall ){
705 ERROR_DECLARE;
706
707 packet_t packet;
708
709 while( true ){
710// printf( "message %d - %d\n", IPC_GET_METHOD( * icall ), NET_NIL_FIRST );
711 switch( IPC_GET_METHOD( * icall )){
712 case NET_NIL_DEVICE_STATE:
713 nil_device_state_msg( 0, IPC_GET_DEVICE( icall ), IPC_GET_STATE( icall ));
714 ipc_answer_0( iid, EOK );
715 break;
716 case NET_NIL_RECEIVED:
717 if( ! ERROR_OCCURRED( packet_translate( eth_globals.net_phone, & packet, IPC_GET_PACKET( icall )))){
718 ERROR_CODE = nil_received_msg( 0, IPC_GET_DEVICE( icall ), packet, 0 );
719 }
720 ipc_answer_0( iid, ( ipcarg_t ) ERROR_CODE );
721 break;
722 default:
723 ipc_answer_0( iid, ( ipcarg_t ) ENOTSUP );
724 }
725 iid = async_get_call( icall );
726 }
727}
728
729/** @}
730 */
Note: See TracBrowser for help on using the repository browser.