Subversion Repositories HelenOS

Rev

Rev 4075 | 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 <stdio.h>
  41. #include <string.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/ethernet_protocols.h"
  52. #include "../../include/protocol_map.h"
  53. #include "../../netif/device.h"
  54.  
  55. #include "../../structures/measured_strings.h"
  56. #include "../../structures/packet/packet.h"
  57. #include "../../structures/packet/packet_client.h"
  58.  
  59. #include "eth.h"
  60. #include "eth_header.h"
  61. //#include "eth_messages.h"
  62. #include "eth_module.h"
  63.  
  64. #define ETH_PREFIX      ( sizeof( eth_header_t ) + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ))
  65. #define ETH_SUFFIX      4
  66. #define ETH_MAX_CONTENT ( ETH_MIN_PROTO - 1 )
  67. #define ETH_MIN_CONTENT 46
  68. #define ETH_PADDING     ETH_SUFFIX
  69.  
  70. /** Returns the device identifier message parameter.
  71.  */
  72. #define IPC_GET_DEVICE( call )      ( device_id_t ) IPC_GET_ARG1( * call )
  73.  
  74. /** Returns the packet identifier message parameter.
  75.  */
  76. #define IPC_GET_PACKET( call )      ( packet_id_t ) IPC_GET_ARG2( * call )
  77.  
  78. /** Returns the protocol service message parameter.
  79.  */
  80. #define IPC_GET_PROTO( call )       ( services_t ) IPC_GET_ARG1( * call )
  81.  
  82. /** Returns the device driver service message parameter.
  83.  */
  84. #define IPC_GET_SERVICE( call )     ( services_t ) IPC_GET_ARG2( * call )
  85.  
  86. #define IPC_GET_MTU( call )         ( size_t ) IPC_GET_ARG3( * call )
  87.  
  88. #define IPC_GET_PHONE( call )       ( int ) IPC_GET_ARG5( * call )
  89.  
  90. #define IPC_SET_ADDR( answer )      (( size_t * ) & IPC_GET_ARG1( * answer ))
  91. #define IPC_SET_PREFIX( answer )    (( size_t * ) & IPC_GET_ARG2( * answer ))
  92. #define IPC_SET_CONTENT( answer )   (( size_t * ) & IPC_GET_ARG3( * answer ))
  93. #define IPC_SET_SUFFIX( answer )    (( size_t * ) & IPC_GET_ARG4( * answer ))
  94.  
  95. typedef enum eth_addr_type  eth_addr_type_t;
  96. typedef eth_addr_type_t *   eth_addr_type_ref;
  97.  
  98. enum eth_addr_type{
  99.     ETH_LOCAL_ADDR,
  100.     ETH_BROADCAST_ADDR
  101. };
  102.  
  103. /** Ethernet global data.
  104.  */
  105. eth_globals_t   eth_globals;
  106.  
  107. /** Processes IPC messages from the registered device driver modules in an infinite loop.
  108.  *  @param iid The message identifier. Input parameter.
  109.  *  @param icall The message parameters. Input/output parameter.
  110.  */
  111. void    eth_receiver( ipc_callid_t iid, ipc_call_t * icall );
  112.  
  113. DEVICE_MAP_IMPLEMENT( eth_devices, eth_device_t )
  114.  
  115. INT_MAP_IMPLEMENT( eth_protos, eth_proto_t )
  116.  
  117. int eth_device_message( device_id_t device_id, services_t service, size_t mtu );
  118. int eth_receive_message( device_id_t device_id, packet_t packet );
  119. int eth_packet_space_message( device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix );
  120. int eth_addr_message( device_id_t device_id, eth_addr_type_t type, measured_string_ref * address );
  121. int eth_register_message( services_t service, int phone );
  122. int eth_send_message( device_id_t device_id, packet_t packet, services_t sender );
  123. int eth_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count );
  124. void    eth_receiver( ipc_callid_t iid, ipc_call_t * icall );
  125.  
  126. int eth_initialize( void ){
  127.     ERROR_DECLARE;
  128.  
  129.     rwlock_initialize( & eth_globals.devices_lock );
  130.     rwlock_initialize( & eth_globals.protos_lock );
  131.     rwlock_write_lock( & eth_globals.devices_lock );
  132.     rwlock_write_lock( & eth_globals.protos_lock );
  133.     eth_globals.broadcast_addr = measured_string_create_bulk( "\xFF\xFF\xFF\xFF\xFF\xFF", CONVERT_SIZE( uint8_t, char, ETH_ADDR ));
  134.     if( ! eth_globals.broadcast_addr ) return ENOMEM;
  135.     ERROR_PROPAGATE( eth_devices_initialize( & eth_globals.devices ));
  136.     if( ERROR_OCCURRED( eth_protos_initialize( & eth_globals.protos ))){
  137.         eth_devices_destroy( & eth_globals.devices );
  138.         return ERROR_CODE;
  139.     }
  140.     rwlock_write_unlock( & eth_globals.protos_lock );
  141.     rwlock_write_unlock( & eth_globals.devices_lock );
  142.     return EOK;
  143. }
  144.  
  145. int eth_device_message( device_id_t device_id, services_t service, size_t mtu ){
  146.     ERROR_DECLARE;
  147.  
  148.     aid_t           message;
  149.     ipc_call_t      answer;
  150.     eth_device_ref  device;
  151.     int             result;
  152.  
  153.     rwlock_write_lock( & eth_globals.devices_lock );
  154.     // an existing device?
  155.     device = eth_devices_find( & eth_globals.devices, device_id );
  156.     if( device ){
  157.         if( device->service == service ){
  158.             // update mtu
  159.             device->mtu = mtu;
  160.             rwlock_write_unlock( & eth_globals.devices_lock );
  161.             return EOK;
  162.         }else{
  163.             rwlock_write_unlock( & eth_globals.devices_lock );
  164.             return EEXIST;
  165.         }
  166.     }else{
  167.         // create a new device
  168.         device = ( eth_device_ref ) malloc( sizeof( eth_device_t ));
  169.         if( ! device ) return ENOMEM;
  170.         device->device_id = device_id;
  171.         device->service = service;
  172.         device->mtu = mtu;
  173.         // bind the device driver
  174.         device->phone = bind_service( device->service, device->device_id, SERVICE_ETHERNET, 0, eth_receiver );
  175.         // get hardware address
  176.         message = async_send_1( device->phone, NET_NETIF_GET_ADDR, device->device_id, & answer );
  177.         if( ERROR_OCCURRED( measured_strings_return( device->phone, & device->addr, & device->addr_data, 1 ))){
  178.             rwlock_write_unlock( & eth_globals.devices_lock );
  179.             free( device );
  180.             async_wait_for( message, NULL );
  181.             return ERROR_CODE;
  182.         }
  183.         async_wait_for( message, ( ipcarg_t * ) & result );
  184.         if( ERROR_OCCURRED( result )){
  185.             rwlock_write_unlock( & eth_globals.devices_lock );
  186.             free( device->addr );
  187.             free( device->addr_data );
  188.             free( device );
  189.             return ERROR_CODE;
  190.         }
  191.         // add to the cache
  192.         if( ERROR_OCCURRED( eth_devices_add( & eth_globals.devices, device->device_id, device ))){
  193.             rwlock_write_unlock( & eth_globals.devices_lock );
  194.             free( device->addr );
  195.             free( device->addr_data );
  196.             free( device );
  197.             return ERROR_CODE;
  198.         }
  199.     }
  200.     rwlock_write_unlock( & eth_globals.devices_lock );
  201.     return EOK;
  202. }
  203.  
  204. int eth_receive_message( device_id_t device_id, packet_t packet ){
  205.     ERROR_DECLARE;
  206.  
  207.     eth_header_ex_ref   header;
  208.     size_t              length;
  209.     int                 type;
  210.     eth_proto_ref       proto;
  211.     size_t              size;
  212.  
  213.     length = packet_get_data_length( packet );
  214.     if( length <= sizeof( eth_header_t ) + ETH_MIN_CONTENT + ETH_PADDING ) return EINVAL;
  215.     // TODO check CRC padding?
  216.     header = ( eth_header_ex_ref ) packet_get_data( packet );
  217.     type = ntohs( header->header.ethertype );
  218.     if( type >= ETH_MIN_PROTO ){
  219.         // DIX Ethernet
  220.         size = sizeof( eth_header_t );
  221.     }else{
  222.         // TODO check length?
  223.         // translate "LSAP" values
  224.         if(( header->lsap.dsap == ETH_RAW ) && ( header->lsap.ssap == ETH_RAW )){
  225.             // raw packet
  226.             // discard
  227.             return EINVAL;
  228.         }else if(( header->lsap.dsap == ETH_LSAP_SNAP ) && ( header->lsap.ssap == ETH_LSAP_SNAP )){
  229.             // IEEE 802.3 SNAP
  230.             // organization code not supported
  231.             type = ntohs( header->snap.ethertype );
  232.             size = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t) + sizeof( eth_header_snap_t);
  233.         }else{
  234.             // IEEE 802.3 + 802.2 LSAP
  235.             // TODO lsap numbers
  236.             type = header->lsap.dsap;
  237.             size = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t);
  238.         }
  239.     }
  240.     rwlock_write_lock( & eth_globals.protos_lock );
  241.     proto = eth_protos_find( & eth_globals.protos, type );
  242.     if( ! proto ){
  243.         rwlock_write_unlock( & eth_globals.protos_lock );
  244.         return ENOENT;
  245.     }
  246.     if( ERROR_OCCURRED( packet_set_addr( packet, header->header.src, header->header.dest, ETH_ADDR ))
  247.     || ERROR_OCCURRED( packet_trim( packet, size, ETH_PADDING ))){
  248.         rwlock_write_unlock( & eth_globals.protos_lock );
  249.         return ERROR_CODE;
  250.     }
  251.     async_msg_2( proto->phone, NET_IL_RECEIVED, device_id, packet_get_id( packet ));
  252.     rwlock_write_unlock( & eth_globals.protos_lock );
  253.     return EOK;
  254. }
  255.  
  256. int eth_packet_space_message( device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix ){
  257.     eth_device_ref  device;
  258.  
  259.     if( !( addr_len && prefix && content && suffix )) return EINVAL;
  260.     rwlock_write_lock( & eth_globals.devices_lock );
  261.     device = eth_devices_find( & eth_globals.devices, device_id );
  262.     if( ! device ){
  263.         rwlock_write_unlock( & eth_globals.devices_lock );
  264.         return ENOENT;
  265.     }
  266.     * content = (  ETH_MAX_CONTENT > device->mtu ) ? device->mtu : ETH_MAX_CONTENT;
  267.     rwlock_write_unlock( & eth_globals.devices_lock );
  268.     * addr_len = ETH_ADDR;
  269.     * prefix = ETH_PREFIX;
  270.     * suffix = ETH_SUFFIX;
  271.     return EOK;
  272. }
  273.  
  274. int eth_addr_message( device_id_t device_id, eth_addr_type_t type, measured_string_ref * address ){
  275.     eth_device_ref  device;
  276.  
  277.     if( ! address ) return EINVAL;
  278.     if( type == ETH_BROADCAST_ADDR ){
  279.         * address = eth_globals.broadcast_addr;
  280.     }else{
  281.         rwlock_write_lock( & eth_globals.devices_lock );
  282.         device = eth_devices_find( & eth_globals.devices, device_id );
  283.         if( ! device ){
  284.             rwlock_write_unlock( & eth_globals.devices_lock );
  285.             return ENOENT;
  286.         }
  287.         * address = device->addr;
  288.         rwlock_write_unlock( & eth_globals.devices_lock );
  289.     }
  290.     return ( * address ) ? EOK : ENOENT;
  291. }
  292.  
  293. int eth_register_message( services_t service, int phone ){
  294.     ERROR_DECLARE;
  295.  
  296.     eth_proto_ref   proto;
  297.     int             protocol;
  298.  
  299.     protocol = protocol_map( SERVICE_ETHERNET, service );
  300.     if( ! protocol ) return ENOENT;
  301.     rwlock_write_lock( & eth_globals.protos_lock );
  302.     proto = eth_protos_find( & eth_globals.protos, protocol );
  303.     if( proto ){
  304.         proto->phone = phone;
  305.         rwlock_write_unlock( & eth_globals.protos_lock );
  306.         return EOK;
  307.     }else{
  308.         proto = ( eth_proto_ref ) malloc( sizeof( eth_proto_t ));
  309.         if( ! proto ){
  310.             rwlock_write_unlock( & eth_globals.protos_lock );
  311.             return ENOMEM;
  312.         }
  313.         proto->service = service;
  314.         proto->protocol = protocol;
  315.         proto->phone = phone;
  316.         if( ERROR_OCCURRED( eth_protos_add( & eth_globals.protos, protocol, proto ))){
  317.             rwlock_write_unlock( & eth_globals.protos_lock );
  318.             free( proto );
  319.             return ERROR_CODE;
  320.         }
  321.     }
  322.     rwlock_write_unlock( & eth_globals.protos_lock );
  323.     return EOK;
  324. }
  325.  
  326. int eth_send_message( device_id_t device_id, packet_t packet, services_t sender ){
  327.     ERROR_DECLARE;
  328.  
  329.     eth_device_ref      device;
  330.     eth_header_ex_ref   header;
  331.     uint8_t *           src;
  332.     uint8_t *           dest;
  333.     int                 length;
  334.     int                 i;
  335.  
  336.     header = PACKET_PREFIX( packet, eth_header_ex_t );
  337.     if( ! header ) return ENOMEM;
  338.     for( i = 0; i < 7; ++ i ) header->header.preamble[ i ] = ETH_PREAMBLE;
  339.     header->header.sfd = ETH_SFD;
  340.     length = packet_get_addr( packet, & src, & dest );
  341.     if( length < 0 ) return length;
  342.     if( length < ETH_ADDR ) return EINVAL;
  343.     // TODO src set?
  344.     // TODO set addresses
  345.     length = packet_get_data_length( packet );
  346.     if( length > ETH_MAX_CONTENT ) return EINVAL;
  347.     if( length < ETH_MIN_CONTENT ){
  348.         // TODO pad zeros
  349.     }
  350.     header->header.ethertype = htons( length );
  351.     header->lsap.dsap = 0xAA;
  352.     header->lsap.ssap = header->lsap.dsap;
  353.     header->lsap.ctrl = 0;
  354.     for( i = 0; i < 3; ++ i ) header->snap.proto[ i ] = 0;
  355.     header->snap.ethertype = htons( protocol_map( SERVICE_ETHERNET, sender ));
  356.     if( ! header ) return ENOENT;
  357.     // TODO eth padding
  358.     if( ! packet_suffix( packet, ETH_PADDING )){
  359.         return ENOMEM;
  360.     }
  361.    
  362.     rwlock_write_lock( & eth_globals.devices_lock );
  363.     rwlock_write_unlock( & eth_globals.devices_lock );
  364.     return EOK;
  365. }
  366.  
  367. int eth_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  368.     ERROR_DECLARE;
  369.  
  370.     measured_string_ref address;
  371.     packet_t            packet;
  372.  
  373.     * answer_count = 0;
  374.     switch( IPC_GET_METHOD( * call )){
  375.         case IPC_M_PHONE_HUNGUP:
  376.             return EOK;
  377.         case NET_NIL_DEVICE:
  378.             return eth_device_message( IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), IPC_GET_MTU( call ));
  379.         case NET_NIL_SEND:
  380.             ERROR_PROPAGATE( packet_translate( eth_globals.networking_phone, & packet, IPC_GET_PACKET( call )));
  381.             return eth_send_message( IPC_GET_DEVICE( call ), packet, IPC_GET_SERVICE( call ));
  382.         case NET_NIL_PACKET_SPACE:
  383.             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 )));
  384.             * answer_count = 3;
  385.             return EOK;
  386.         case NET_NIL_ADDR:
  387.             rwlock_read_lock( & eth_globals.devices_lock );
  388.             if( ! ERROR_OCCURRED( eth_addr_message( IPC_GET_DEVICE( call ), ETH_LOCAL_ADDR, & address ))){
  389.                  ERROR_CODE = measured_strings_reply( address, 1 );
  390.             }
  391.             rwlock_read_unlock( & eth_globals.devices_lock );
  392.             return ERROR_CODE;
  393.         case NET_NIL_BROADCAST_ADDR:
  394.             rwlock_read_lock( & eth_globals.devices_lock );
  395.             if( ! ERROR_OCCURRED( eth_addr_message( IPC_GET_DEVICE( call ), ETH_BROADCAST_ADDR, & address ))){
  396.                  ERROR_CODE = measured_strings_reply( address, 1 );
  397.             }
  398.             rwlock_read_unlock( & eth_globals.devices_lock );
  399.             return ERROR_CODE;
  400.         case IPC_M_CONNECT_TO_ME:
  401.             return eth_register_message( IPC_GET_PROTO( call ), IPC_GET_PHONE( call ));
  402.     }
  403.     return ENOTSUP;
  404. }
  405.  
  406. void eth_receiver( ipc_callid_t iid, ipc_call_t * icall ){
  407.     ERROR_DECLARE;
  408.  
  409.     packet_t        packet;
  410.  
  411.     while( true ){
  412.         switch( IPC_GET_METHOD( * icall )){
  413.             case NET_NIL_DEVICE_STATE:
  414.                 //TODO clear device if off?
  415.                 break;
  416.             case NET_NIL_RECEIVED:
  417.                 if( ! ERROR_OCCURRED( packet_translate( eth_globals.networking_phone, & packet, IPC_GET_PACKET( icall )))){
  418.                     ERROR_CODE = eth_receive_message( IPC_GET_DEVICE( icall ), packet );
  419.                 }
  420.                 ipc_answer_0( iid, ERROR_CODE );
  421.                 break;
  422.             default:
  423.                 ipc_answer_0( iid, ENOTSUP );
  424.         }
  425.         iid = async_get_call( icall );
  426.     }
  427. }
  428.  
  429. /** @}
  430.  */
  431.