Subversion Repositories HelenOS

Rev

Rev 4307 | Rev 4350 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.  
  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 "../../include/byteorder.h"
  51. #include "../../include/crc.h"
  52. #include "../../include/ethernet_lsap.h"
  53. #include "../../include/ethernet_protocols.h"
  54. #include "../../include/protocol_map.h"
  55. #include "../../include/device.h"
  56. #include "../../include/netif_interface.h"
  57. #include "../../include/net_interface.h"
  58. #include "../../include/nil_interface.h"
  59. #include "../../include/il_interface.h"
  60.  
  61. #include "../../structures/measured_strings.h"
  62. #include "../../structures/packet/packet_client.h"
  63.  
  64. #include "../nil_module.h"
  65.  
  66. #include "eth.h"
  67. #include "eth_header.h"
  68.  
  69. #define ETH_PREFIX      ( sizeof( eth_header_t ) + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ))
  70. #define ETH_SUFFIX      sizeof( eth_fcs_t )
  71. #define ETH_MAX_CONTENT 1500
  72. #define ETH_MIN_CONTENT 46
  73. #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 ))
  74. #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 ))
  75.  
  76. #define ETH_DUMMY_SHIFT 0
  77. #define ETH_MODE_SHIFT  1
  78.  
  79. /** Dummy device flag.
  80.  *  Preamble and FCS are mandatory part of the packets.
  81.  */
  82. #define ETH_DUMMY               ( 1 << ETH_DUMMY_SHIFT )
  83. #define IS_DUMMY( flags )       (( flags ) & ETH_DUMMY )
  84.  
  85. /** Device mode flags.
  86.  *  @see ETH_DIX
  87.  *  @see ETH_8023_2_LSAP
  88.  *  @see ETH_8023_2_SNAP
  89.  */
  90. #define ETH_MODE_MASK           ( 3 << ETH_MODE_SHIFT )
  91. #define ETH_DIX                 ( 1 << ETH_MODE_SHIFT )
  92. #define IS_DIX( flags )         ((( flags ) & ETH_MODE_MASK ) == ETH_DIX )
  93. #define ETH_8023_2_LSAP         ( 2 << ETH_MODE_SHIFT )
  94. #define IS_8023_2_LSAP( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_8023_2_LSAP )
  95. #define ETH_8023_2_SNAP         ( 3 << ETH_MODE_SHIFT )
  96. #define IS_8023_2_SNAP( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_8023_2_SNAP )
  97.  
  98. typedef enum eth_addr_type  eth_addr_type_t;
  99. typedef eth_addr_type_t *   eth_addr_type_ref;
  100.  
  101. enum eth_addr_type{
  102.     ETH_LOCAL_ADDR,
  103.     ETH_BROADCAST_ADDR
  104. };
  105.  
  106. /** Ethernet global data.
  107.  */
  108. eth_globals_t   eth_globals;
  109.  
  110. /** Processes IPC messages from the registered device driver modules in an infinite loop.
  111.  *  @param iid The message identifier. Input parameter.
  112.  *  @param icall The message parameters. Input/output parameter.
  113.  */
  114. void    eth_receiver( ipc_callid_t iid, ipc_call_t * icall );
  115.  
  116. DEVICE_MAP_IMPLEMENT( eth_devices, eth_device_t )
  117.  
  118. INT_MAP_IMPLEMENT( eth_protos, eth_proto_t )
  119.  
  120. int eth_device_message( device_id_t device_id, services_t service, size_t mtu );
  121. int nil_receive_msg( int nil_phone, device_id_t device_id, packet_t packet );
  122. int nil_register_message( services_t service, int phone );
  123. int eth_packet_space_message( device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix );
  124. int eth_addr_message( device_id_t device_id, eth_addr_type_t type, measured_string_ref * address );
  125. int eth_send_message( device_id_t device_id, packet_t packet, services_t sender );
  126. eth_proto_ref   eth_process_packet( int flags, packet_t packet );
  127. int eth_prepare_packet( int flags, packet_t packet, uint8_t * src_addr, int ethertype );
  128.  
  129. int nil_device_state_msg( int nil_phone, device_id_t device_id, int state ){
  130.     int             index;
  131.     eth_proto_ref   proto;
  132.  
  133.     //TODO clear device if off?
  134.     rwlock_read_lock( & eth_globals.protos_lock );
  135.     for( index = eth_protos_count( & eth_globals.protos ) - 1; index >= 0; -- index ){
  136.         proto = eth_protos_get_index( & eth_globals.protos, index );
  137.         if( proto && proto->phone ) il_device_state_msg( proto->phone, device_id, state );
  138.     }
  139.     rwlock_read_unlock( & eth_globals.protos_lock );
  140.     return EOK;
  141. }
  142.  
  143. int nil_initialize( int net_phone ){
  144.     ERROR_DECLARE;
  145.  
  146.     rwlock_initialize( & eth_globals.devices_lock );
  147.     rwlock_initialize( & eth_globals.protos_lock );
  148.     rwlock_write_lock( & eth_globals.devices_lock );
  149.     rwlock_write_lock( & eth_globals.protos_lock );
  150.     eth_globals.net_phone = net_phone;
  151.     eth_globals.broadcast_addr = measured_string_create_bulk( "\xFF\xFF\xFF\xFF\xFF\xFF", CONVERT_SIZE( uint8_t, char, ETH_ADDR ));
  152.     if( ! eth_globals.broadcast_addr ) return ENOMEM;
  153.     ERROR_PROPAGATE( eth_devices_initialize( & eth_globals.devices ));
  154.     if( ERROR_OCCURRED( eth_protos_initialize( & eth_globals.protos ))){
  155.         eth_devices_destroy( & eth_globals.devices );
  156.         return ERROR_CODE;
  157.     }
  158.     rwlock_write_unlock( & eth_globals.protos_lock );
  159.     rwlock_write_unlock( & eth_globals.devices_lock );
  160.     return EOK;
  161. }
  162.  
  163. int eth_device_message( device_id_t device_id, services_t service, size_t mtu ){
  164.     ERROR_DECLARE;
  165.  
  166.     eth_device_ref  device;
  167.     int             index;
  168.     measured_string_t   names[ 2 ] = {{ "ETH_MODE", 8 }, { "ETH_DUMMY", 9 }};
  169.     measured_string_ref configuration;
  170.     int                 count = 2;
  171.     char *              data;
  172.  
  173.     rwlock_write_lock( & eth_globals.devices_lock );
  174.     // an existing device?
  175.     device = eth_devices_find( & eth_globals.devices, device_id );
  176.     if( device ){
  177.         if( device->service != service ){
  178.             printf( "Device %d already exists\n", device->device_id );
  179.             rwlock_write_unlock( & eth_globals.devices_lock );
  180.             return EEXIST;
  181.         }else{
  182.             // update mtu
  183.             device->mtu = mtu;
  184.             printf( "Device %d already exists:\tMTU\t= %d\n", device->device_id, device->mtu );
  185.         }
  186.     }else{
  187.         // create a new device
  188.         device = ( eth_device_ref ) malloc( sizeof( eth_device_t ));
  189.         if( ! device ) return ENOMEM;
  190.         device->device_id = device_id;
  191.         device->service = service;
  192.         device->flags = 0;
  193.         device->mtu = (( mtu > 0 ) && ( mtu <= ETH_MAX_TAGGED_CONTENT( device->flags ))) ? mtu : ETH_MAX_TAGGED_CONTENT( device->flags );
  194.         configuration = & names[ 0 ];
  195.         if( ERROR_OCCURRED( net_get_device_conf_req( eth_globals.net_phone, device->device_id, & configuration, count, & data ))){
  196.             rwlock_write_unlock( & eth_globals.devices_lock );
  197.             free( device );
  198.             return ERROR_CODE;
  199.         }
  200.         if( configuration ){
  201.             if( ! str_lcmp( configuration[ 0 ].value, "DIX", configuration[ 0 ].length )){
  202.                 device->flags |= ETH_DIX;
  203.             }else if( ! str_lcmp( configuration[ 0 ].value, "8023_2_LSAP", configuration[ 0 ].length )){
  204.                 // TODO 8023_2_LSAP
  205.                 printf( "8023_2_LSAP is not supported (yet?), DIX used instead\n" );
  206.                 device->flags |= ETH_DIX;
  207.             }else device->flags |= ETH_8023_2_SNAP;
  208.             if(( configuration[ 1 ].value ) && ( configuration[ 1 ].value[ 0 ] == 'y' )){
  209.                 device->flags |= ETH_DUMMY;
  210.             }
  211.             net_free_settings( configuration, data );
  212.         }else{
  213.             device->flags |= ETH_8023_2_SNAP;
  214.         }
  215.         // bind the device driver
  216.         device->phone = netif_bind_service( device->service, device->device_id, SERVICE_ETHERNET, eth_receiver );
  217.         if( device->phone < 0 ){
  218.             rwlock_write_unlock( & eth_globals.devices_lock );
  219.             free( device );
  220.             return device->phone;
  221.         }
  222.         // get hardware address
  223.         if( ERROR_OCCURRED( netif_get_addr( device->phone, device->device_id, & device->addr, & device->addr_data ))){
  224.             rwlock_write_unlock( & eth_globals.devices_lock );
  225.             free( device );
  226.             return ERROR_CODE;
  227.         }
  228.         // add to the cache
  229.         index = eth_devices_add( & eth_globals.devices, device->device_id, device );
  230.         if( index < 0 ){
  231.             rwlock_write_unlock( & eth_globals.devices_lock );
  232.             free( device->addr );
  233.             free( device->addr_data );
  234.             free( device );
  235.             return index;
  236.         }
  237.         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 );
  238.     }
  239.     rwlock_write_unlock( & eth_globals.devices_lock );
  240.     return EOK;
  241. }
  242.  
  243. eth_proto_ref eth_process_packet( int flags, packet_t packet ){
  244.     ERROR_DECLARE;
  245.  
  246.     eth_header_ex_ref   header;
  247.     size_t              length;
  248.     int                 type;
  249.     size_t              prefix;
  250.     size_t              suffix;
  251.     eth_fcs_ref         fcs;
  252.  
  253.     length = packet_get_data_length( packet );
  254.     if( IS_DUMMY( flags )){
  255.         packet_trim( packet, sizeof( eth_preamble_t ), 0 );
  256.     }
  257.     if( length < sizeof( eth_header_t ) + ETH_MIN_CONTENT + ( IS_DUMMY( flags ) ? ETH_SUFFIX : 0 )) return NULL;
  258.     header = ( eth_header_ex_ref ) packet_get_data( packet );
  259.     type = ntohs( header->header.ethertype );
  260.     if( type >= ETH_MIN_PROTO ){
  261.         // DIX Ethernet
  262.         prefix = sizeof( eth_header_t );
  263.         suffix = 0;
  264.         fcs = (( void * ) header ) + length - sizeof( eth_fcs_t );
  265.     }else if( type <= ETH_MAX_CONTENT ){
  266.         // translate "LSAP" values
  267.         if(( header->lsap.dsap == ETH_LSAP_GLSAP ) && ( header->lsap.ssap == ETH_LSAP_GLSAP )){
  268.             // raw packet
  269.             // discard
  270.             return NULL;
  271.         }else if(( header->lsap.dsap == ETH_LSAP_SNAP ) && ( header->lsap.ssap == ETH_LSAP_SNAP )){
  272.             // IEEE 802.3 + 802.2 + LSAP + SNAP
  273.             // organization code not supported
  274.             type = ntohs( header->snap.ethertype );
  275.             prefix = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t );
  276.         }else{
  277.             // IEEE 802.3 + 802.2 LSAP
  278.             type = lsap_map( header->lsap.dsap );
  279.             prefix = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t);
  280.         }
  281.         suffix = ( type < ETH_MIN_CONTENT ) ? ETH_MIN_CONTENT - type : 0;
  282.         fcs = (( void * ) header ) + prefix + type + suffix;
  283.         suffix += length - prefix - type;
  284.     }else{
  285.         // invalid length/type, should not occurr
  286.         return NULL;
  287.     }
  288.     if( IS_DUMMY( flags )){
  289.         if(( ~ compute_crc32( ~ 0, & header->header.dest, ((( void * ) fcs ) - (( void * ) & header->header.dest )) * 8 )) != ntohl( * fcs )){
  290.             return NULL;
  291.         }
  292.         suffix += sizeof( eth_fcs_t );
  293.     }
  294.     if( ERROR_OCCURRED( packet_set_addr( packet, header->header.src, header->header.dest, ETH_ADDR ))
  295.     || ERROR_OCCURRED( packet_trim( packet, prefix, suffix ))){
  296.         return NULL;
  297.     }
  298.     return eth_protos_find( & eth_globals.protos, type );
  299. }
  300.  
  301. int nil_received_msg( int nil_phone, device_id_t device_id, packet_t packet, services_t target ){
  302.     eth_proto_ref   proto;
  303.     packet_t        next;
  304.     eth_device_ref  device;
  305.     int             flags;
  306.  
  307.     rwlock_read_lock( & eth_globals.devices_lock );
  308.     device = eth_devices_find( & eth_globals.devices, device_id );
  309.     if( ! device ){
  310.         rwlock_read_unlock( & eth_globals.devices_lock );
  311.         return ENOENT;
  312.     }
  313.     flags = device->flags;
  314.     rwlock_read_unlock( & eth_globals.devices_lock );
  315.     rwlock_read_lock( & eth_globals.protos_lock );
  316.     do{
  317.         next = pq_detach( packet );
  318.         proto = eth_process_packet( flags, packet );
  319.         if( proto ){
  320.             il_received_msg( proto->phone, device_id, packet, proto->service );
  321.         }else{
  322.             // drop invalid/unknown
  323.             pq_release( eth_globals.net_phone, packet_get_id( packet ));
  324.         }
  325.         packet = next;
  326.     }while( packet );
  327.     rwlock_read_unlock( & eth_globals.protos_lock );
  328.     return EOK;
  329. }
  330.  
  331. int eth_packet_space_message( device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix ){
  332.     eth_device_ref  device;
  333.  
  334.     if( !( addr_len && prefix && content && suffix )) return EINVAL;
  335.     rwlock_read_lock( & eth_globals.devices_lock );
  336.     device = eth_devices_find( & eth_globals.devices, device_id );
  337.     if( ! device ){
  338.         rwlock_read_unlock( & eth_globals.devices_lock );
  339.         return ENOENT;
  340.     }
  341.     * content = device->mtu;
  342.     rwlock_read_unlock( & eth_globals.devices_lock );
  343.     * addr_len = ETH_ADDR;
  344.     * prefix = ETH_PREFIX;
  345.     * suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
  346.     return EOK;
  347. }
  348.  
  349. int eth_addr_message( device_id_t device_id, eth_addr_type_t type, measured_string_ref * address ){
  350.     eth_device_ref  device;
  351.  
  352.     if( ! address ) return EINVAL;
  353.     if( type == ETH_BROADCAST_ADDR ){
  354.         * address = eth_globals.broadcast_addr;
  355.     }else{
  356.         rwlock_read_lock( & eth_globals.devices_lock );
  357.         device = eth_devices_find( & eth_globals.devices, device_id );
  358.         if( ! device ){
  359.             rwlock_read_unlock( & eth_globals.devices_lock );
  360.             return ENOENT;
  361.         }
  362.         * address = device->addr;
  363.         rwlock_read_unlock( & eth_globals.devices_lock );
  364.     }
  365.     return ( * address ) ? EOK : ENOENT;
  366. }
  367.  
  368. int nil_register_message( services_t service, int phone ){
  369.     eth_proto_ref   proto;
  370.     int             protocol;
  371.     int             index;
  372.  
  373.     protocol = protocol_map( SERVICE_ETHERNET, service );
  374.     if( ! protocol ) return ENOENT;
  375.     rwlock_write_lock( & eth_globals.protos_lock );
  376.     proto = eth_protos_find( & eth_globals.protos, protocol );
  377.     if( proto ){
  378.         proto->phone = phone;
  379.         rwlock_write_unlock( & eth_globals.protos_lock );
  380.         return EOK;
  381.     }else{
  382.         proto = ( eth_proto_ref ) malloc( sizeof( eth_proto_t ));
  383.         if( ! proto ){
  384.             rwlock_write_unlock( & eth_globals.protos_lock );
  385.             return ENOMEM;
  386.         }
  387.         proto->service = service;
  388.         proto->protocol = protocol;
  389.         proto->phone = phone;
  390.         index = eth_protos_add( & eth_globals.protos, protocol, proto );
  391.         if( index < 0 ){
  392.             rwlock_write_unlock( & eth_globals.protos_lock );
  393.             free( proto );
  394.             return index;
  395.         }
  396.     }
  397.     printf( "New protocol registered:\n\tprotocol\t= 0x%x\n\tservice\t= %d\n\tphone\t= %d\n", proto->protocol, proto->service, proto->phone );
  398.     rwlock_write_unlock( & eth_globals.protos_lock );
  399.     return EOK;
  400. }
  401.  
  402. int eth_prepare_packet( int flags, packet_t packet, uint8_t * src_addr, int ethertype ){
  403.     eth_header_ex_ref   header;
  404.     eth_header_ref      header_dix;
  405.     eth_fcs_ref         fcs;
  406.     uint8_t *           src;
  407.     uint8_t *           dest;
  408.     int                 length;
  409.     int                 i;
  410.     void *              padding;
  411.     eth_preamble_ref    preamble;
  412.  
  413.     length = packet_get_addr( packet, & src, & dest );
  414.     if( length < 0 ) return length;
  415.     if( length < ETH_ADDR ) return EINVAL;
  416.     length = packet_get_data_length( packet );
  417.     if( length > ETH_MAX_TAGGED_CONTENT( flags )) return EINVAL;
  418.     if( length < ETH_MIN_TAGGED_CONTENT( flags )){
  419.         padding = packet_suffix( packet, ETH_MIN_TAGGED_CONTENT( flags ) - length );
  420.         if( ! padding ) return ENOMEM;
  421.         bzero( padding, ETH_MIN_TAGGED_CONTENT( flags ) - length );
  422.     }
  423.     if( IS_DUMMY( flags )){
  424.         preamble = PACKET_PREFIX( packet, eth_preamble_t );
  425.         if( ! preamble ) return ENOMEM;
  426.         for( i = 0; i < 7; ++ i ) preamble->preamble[ i ] = ETH_PREAMBLE;
  427.         preamble->sfd = ETH_SFD;
  428.     }
  429.     // TODO LSAP only device
  430.     if( IS_DIX( flags ) || IS_8023_2_LSAP( flags )){
  431.         header_dix = PACKET_PREFIX( packet, eth_header_t );
  432.         header_dix->ethertype = ( uint16_t ) ethertype;
  433.         memcpy( header_dix->src, src_addr, ETH_ADDR );
  434.         memcpy( header_dix->dest, dest, ETH_ADDR );
  435.         src = & header_dix->dest[ 0 ];
  436.     }else if( IS_8023_2_SNAP( flags )){
  437.         header = PACKET_PREFIX( packet, eth_header_ex_t );
  438.         if( ! header ) return ENOMEM;
  439.         header->header.ethertype = htons( length + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ));
  440.         header->lsap.dsap = ( uint16_t ) ETH_LSAP_SNAP;
  441.         header->lsap.ssap = header->lsap.dsap;
  442.         header->lsap.ctrl = 0;
  443.         for( i = 0; i < 3; ++ i ) header->snap.proto[ i ] = 0;
  444.         header->snap.ethertype = ( uint16_t ) ethertype;
  445.         memcpy( header->header.src, src_addr, ETH_ADDR );
  446.         memcpy( header->header.dest, dest, ETH_ADDR );
  447.         src = & header->header.dest[ 0 ];
  448.     }
  449.     if( IS_DUMMY( flags )){
  450.         fcs = PACKET_SUFFIX( packet, eth_fcs_t );
  451.         if( ! fcs ) return ENOMEM;
  452.         * fcs = htonl( ~ compute_crc32( ~ 0, src, ((( void * ) fcs ) - (( void * ) src )) * 8 ));
  453.     }
  454.     return EOK;
  455. }
  456.  
  457. int eth_send_message( device_id_t device_id, packet_t packet, services_t sender ){
  458.     ERROR_DECLARE;
  459.  
  460.     eth_device_ref      device;
  461.     packet_t            next;
  462.     packet_t            tmp;
  463.     int                 ethertype;
  464.  
  465.     ethertype = htons( protocol_map( SERVICE_ETHERNET, sender ));
  466.     if( ! ethertype ){
  467.         pq_release( eth_globals.net_phone, packet_get_id( packet ));
  468.         return EINVAL;
  469.     }
  470.     rwlock_read_lock( & eth_globals.devices_lock );
  471.     device = eth_devices_find( & eth_globals.devices, device_id );
  472.     if( ! device ){
  473.         rwlock_read_unlock( & eth_globals.devices_lock );
  474.         return ENOENT;
  475.     }
  476.     // process packet queue
  477.     next = packet;
  478.     do{
  479.         if( ERROR_OCCURRED( eth_prepare_packet( device->flags, next, ( uint8_t * ) device->addr->value, ethertype ))){
  480.             // release invalid packet
  481.             tmp = pq_detach( next );
  482.             pq_release( eth_globals.net_phone, packet_get_id( next ));
  483.             next = tmp;
  484.         }else{
  485.             next = pq_next( next );
  486.         }
  487.     }while( next );
  488.     // send packet queue
  489.     netif_send_msg( device->phone, device_id, packet, SERVICE_ETHERNET );
  490.     rwlock_read_unlock( & eth_globals.devices_lock );
  491.     return EOK;
  492. }
  493.  
  494. int nil_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  495.     ERROR_DECLARE;
  496.  
  497.     measured_string_ref address;
  498.     packet_t            packet;
  499.  
  500. //  printf( "message %d - %d\n", IPC_GET_METHOD( * call ), NET_NIL_FIRST );
  501.     * answer_count = 0;
  502.     switch( IPC_GET_METHOD( * call )){
  503.         case IPC_M_PHONE_HUNGUP:
  504.             return EOK;
  505.         case NET_NIL_DEVICE:
  506.             return eth_device_message( IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), NIL_GET_MTU( call ));
  507.         case NET_NIL_SEND:
  508.             ERROR_PROPAGATE( packet_translate( eth_globals.net_phone, & packet, IPC_GET_PACKET( call )));
  509.             return eth_send_message( IPC_GET_DEVICE( call ), packet, IPC_GET_SERVICE( call ));
  510.         case NET_NIL_PACKET_SPACE:
  511.             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 )));
  512.             * answer_count = 3;
  513.             return EOK;
  514.         case NET_NIL_ADDR:
  515.             ERROR_PROPAGATE( eth_addr_message( IPC_GET_DEVICE( call ), ETH_LOCAL_ADDR, & address ));
  516.             return measured_strings_reply( address, 1 );
  517.         case NET_NIL_BROADCAST_ADDR:
  518.             ERROR_PROPAGATE( eth_addr_message( IPC_GET_DEVICE( call ), ETH_BROADCAST_ADDR, & address ));
  519.             return measured_strings_reply( address, 1 );
  520.         case IPC_M_CONNECT_TO_ME:
  521.             return nil_register_message( NIL_GET_PROTO( call ), IPC_GET_PHONE( call ));
  522.     }
  523.     return ENOTSUP;
  524. }
  525.  
  526. void eth_receiver( ipc_callid_t iid, ipc_call_t * icall ){
  527.     ERROR_DECLARE;
  528.  
  529.     packet_t        packet;
  530.  
  531.     while( true ){
  532. //      printf( "message %d - %d\n", IPC_GET_METHOD( * icall ), NET_NIL_FIRST );
  533.         switch( IPC_GET_METHOD( * icall )){
  534.             case NET_NIL_DEVICE_STATE:
  535.                 nil_device_state_msg( 0, IPC_GET_DEVICE( icall ), IPC_GET_STATE( icall ));
  536.                 ipc_answer_0( iid, EOK );
  537.                 break;
  538.             case NET_NIL_RECEIVED:
  539.                 if( ! ERROR_OCCURRED( packet_translate( eth_globals.net_phone, & packet, IPC_GET_PACKET( icall )))){
  540.                     ERROR_CODE = nil_received_msg( 0, IPC_GET_DEVICE( icall ), packet, 0 );
  541.                 }
  542.                 ipc_answer_0( iid, ERROR_CODE );
  543.                 break;
  544.             default:
  545.                 ipc_answer_0( iid, ENOTSUP );
  546.         }
  547.         iid = async_get_call( icall );
  548.     }
  549. }
  550.  
  551. /** @}
  552.  */
  553.