Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

eth.c

Go to the documentation of this file.
00001 /*!     \file network/eth.c
00002  *      \brief Ethernet driver.
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update: 2003-11-09
00005  *      \note Copyright (&copy;) 2003 Andrea Righi
00006  */
00007 
00008 #include <const.h>
00009 #include <errno.h>
00010 #include <stdio.h>
00011 #include <string.h>
00012 
00013 #include <arch/mem.h>
00014 #include <arch/i386.h>
00015 
00016 #include <kernel/clock.h>
00017 #include <kernel/console.h>
00018 #include <kernel/kmalloc.h>
00019 #include <kernel/task.h>
00020 
00021 #include <net/arp.h>
00022 #include <net/ip.h>
00023 #include <net/network.h>
00024 #include <net/rtl8139.h>
00025 #include <net/tcp.h>
00026 
00027 #include <net/eth.h>
00028 
00029 extern rtl8139_t *rtl;
00030 
00031 //! Ethernet receive buffer.
00032 eth_buf_t *eth_recv_buf=NULL;
00033 
00034 //! Daemon ethernet tasks 1.
00035 task_t  *eth_recv_thread1=NULL,
00036 //! Daemon ethernet tasks 2.
00037         *eth_recv_thread2=NULL;
00038 
00039 // --- Initialization ------------------------------------------------- //
00040 
00041 //! \brief Initialize the ethernet receive buffer.
00042 void eth_init_buffer()
00043 {
00044         // Create the receive buffer                                    //
00045         eth_recv_buf = kmalloc(sizeof(eth_buf_t));
00046 
00047         // Reset the receive buffer                                     //
00048         memset(eth_recv_buf, 0, sizeof(eth_buf_t));
00049 
00050         // Initialize buffer semaphores                                 //
00051         INIT_MUTEX(&eth_recv_buf->mutex);
00052 }
00053 
00054 // --- RECV routines -------------------------------------------------- //
00055 
00056 //! \brief Receive data from the ethernet layer.
00057 //! \param buf
00058 //!     A buffer where the ethernet received packet will be copied.
00059 //! \param len
00060 //!     The max size of the buffer \p buf.
00061 //! \param flags
00062 //!     Flags.
00063 //! \return The length in bytes of the packet received.
00064 /**
00065  *      \todo \p flags parameter implementation.
00066  */
00067 int recv_eth_packet(ethernet_t *buf, size_t len, int flags)
00068 {
00069         dword IF = GET_IF();
00070 
00071         // If the recv buffer is empty, simply do nothing               //
00072         while(TRUE)
00073         {
00074                 DOWN(&eth_recv_buf->mutex);
00075 
00076                 if ( eth_recv_buf->count==0 )
00077                 {
00078                         UP(&eth_recv_buf->mutex);
00079                         sleep_task( get_curr_task() );
00080                         enable();
00081                         idle();
00082                 }
00083                 else
00084                         // The buffer is not empty!                     //
00085                         break;
00086         }
00087 
00088         // Get the packet from the recv buffer and put it into the      //
00089         // requested pointer                                            //
00090         memcpy(
00091                 buf,
00092                 eth_recv_buf->packet[eth_recv_buf->read].data,
00093                 len = MIN(len, eth_recv_buf->packet[eth_recv_buf->read].length)
00094         );
00095         // Update the read pointer and the recv buffer counter          //
00096         eth_recv_buf->read = (eth_recv_buf->read + 1) % ETH_RECV_BUF_DIM;
00097         (eth_recv_buf->count)--;
00098 
00099         UP(&eth_recv_buf->mutex);
00100         SET_IF(IF);
00101 
00102         // Return the length of the received packet                     //
00103         return( len );
00104 }
00105 
00106 //! \brief
00107 //!     This daemon permanently reads packets from the recv buffer and
00108 //!     send them to the opportune layer.
00109 void eth_recv_daemon()
00110 {
00111         unsigned i;
00112         size_t len;
00113         union
00114         {
00115                 uint8_t raw[ETH_FRAME_LEN];
00116                 ethernet_t eth;
00117         } packet;
00118 
00119         while(TRUE)
00120         {
00121                 // Reset the buffer                                     //
00122                 memset(packet.raw, 0, sizeof(packet.raw));
00123                 // Listen the buffer                                    //
00124                 len = recv_eth_packet(&packet.eth, sizeof(packet.raw), 0);
00125 
00126                 // Send the packet to the right layer                   //
00127                 switch( ntohs(packet.eth.type) )
00128                 {
00129                         case ETH_FRAME_ARP:
00130                                 to_arp_layer((arp_t *)(packet.eth.data));
00131                         break;
00132 
00133                         case ETH_FRAME_IP:
00134                                 to_ip_layer((ip_t *)(packet.eth.data));
00135                         break;
00136 
00137                         default:
00138                                 // Unknown magic number                 //
00139                                 kprintf("\n\rPACK TYPE  = UNKNOWN (%04X)", htons(packet.eth.type));
00140                                 // Dump the packet content              //
00141                                 kprintf("\n\rDUMP:\n\r");
00142                                 for (i=0; i<len; i++)
00143                                         kprintf("%02X ", packet.eth.data[i]);
00144                         break;
00145                 }
00146         }
00147 }
00148 
00149 //! \brief
00150 //!     Process an ethernet packet received from the physical layer.
00151 //! \param packet The ethernet packet received.
00152 //! \param len The size of the packet.
00153 void to_eth_layer(ethernet_t *packet, size_t len)
00154 {
00155         DOWN(&eth_recv_buf->mutex);
00156 
00157         #ifdef ETH_DEBUG
00158         // Strip the ethernet header                                    //
00159         kprintf("\n\rMAC DEST   = %02x:%02x:%02x:%02x:%02x:%02x",
00160                 packet->dst[0], packet->dst[1], packet->dst[2],
00161                 packet->dst[3], packet->dst[4], packet->dst[5]);
00162         kprintf("\n\rMAC SOURCE = %02x:%02x:%02x:%02x:%02x:%02x",
00163                 packet->src[0], packet->src[1], packet->src[2],
00164                 packet->src[3], packet->src[4], packet->src[5]);
00165         kprintf("\n\rPACK TYPE  = %04x", ntohs(packet->type));
00166         kprintf("\n\rTOT LENGTH = %u bytes", len);
00167         #endif
00168 
00169         // Store the packet data into the send buffer                   //
00170         memcpy(
00171                 eth_recv_buf->packet[eth_recv_buf->write].data,
00172                 packet,
00173                 len = MIN(len, ETH_FRAME_LEN)
00174         );
00175         // Store the packet length                                      //
00176         eth_recv_buf->packet[eth_recv_buf->write].length = len;
00177         // Update the recv buffer write pointer                         //
00178         eth_recv_buf->write = (eth_recv_buf->write + 1) % ETH_RECV_BUF_DIM;
00179 
00180         if (eth_recv_buf->count <= ETH_RECV_BUF_DIM)
00181                 // Update the packet counter                            //
00182                 (eth_recv_buf->count)++;
00183         else
00184                 // The oldest packet has been overwritten, so update    //
00185                 // also the read pointer                                //
00186                 eth_recv_buf->read = (eth_recv_buf->read + 1) % ETH_RECV_BUF_DIM;
00187 
00188         UP(&eth_recv_buf->mutex);
00189 
00190         // Wakeup the receive daemons                                   //
00191         wakeup_task( eth_recv_thread1 );
00192         wakeup_task( eth_recv_thread2 );
00193 }
00194 
00195 // --- SEND routines -------------------------------------------------- //
00196 
00197 //! \brief Send an ethernet packet to the physiscal layer.
00198 //! \param to The destination ethernet address (MAC).
00199 //! \param data The buffer of data to be sent.
00200 //! \param len The size of the buffer of data to be sent.
00201 //! \param type The packet type.
00202 //! \return
00203 //!     \li The number of bytes sent in case of success.
00204 //!     \li -#ENOMEM cannot allocate the packet structure.
00205 //!     \li -#ENXIO no ethernet device found.
00206 int send_eth_packet(const uint8_t *to, const void *data, size_t len, uint16_t type)
00207 {
00208         uint8_t *packet;
00209         uint8_t *mac_addr;
00210 
00211         // Analyze the packet length (must be less than ETH_MTU)        //
00212         // TODO: if the packet length if great than ETH_MTU             //
00213         // perform a packet fragmentation.                              //
00214         len = MIN(len, ETH_MTU);
00215 
00216         // Create the ethernet packet                                   //
00217         packet = kmalloc( MAX(len+ETH_HEAD_LEN, ETH_MIN_LEN) );
00218         if (!packet)
00219                 return(-ENOMEM);
00220 
00221         // Get the local mac address                                    //
00222         if ( (mac_addr = get_eth_mac_addr()) == NULL )
00223                 // No such device or address!                           //
00224                 return(-ENXIO);
00225 
00226         // Add the ethernet header to the packet                        //
00227         memcpy(packet, to, ETH_ADDR_LEN);
00228         memcpy(packet + ETH_ADDR_LEN, mac_addr, ETH_ADDR_LEN);
00229         memcpy(packet + 2 * ETH_ADDR_LEN, &type, sizeof(uint16_t));
00230 
00231         // Copy the data into the packet                                //
00232         memcpy(packet + ETH_HEAD_LEN, data, len);
00233 
00234         // Adjust the packet length including the size of the header    //
00235         len += ETH_HEAD_LEN;
00236 
00237         // Auto-pad! Send a minimum payload (another 4 bytes are        //
00238         // sent automatically for the FCS, totalling to 64 bytes)       //
00239         // It is the minimum length of an ethernet packet.              //
00240         while (len < ETH_MIN_LEN)
00241                 packet[len++] = '\0';
00242 
00243         // Go to the physical layer                                     //
00244         len = send_rtl8139_packet(get_rtl8139_device(), packet, len);
00245 
00246         // Free the memory of the packet                                //
00247         kfree(packet);
00248 
00249         // Return the bytes transmitted at this level                   //
00250         return(len);
00251 }
00252 
00253 // --- Interface routines --------------------------------------------- //
00254 
00255 //! \brief
00256 //!     Check if the ethernet device has been configured in
00257 //!     promiscuous mode.
00258 //! \return
00259 //!     \li #TRUE the ethernet card is in promiscuous mode;
00260 //!     \li #FALSE the ethernet card is not in promiscuous mode.
00261 bool is_eth_promisc()
00262 {
00263         return( get_rtl8139_device()->promisc );
00264 }
00265 
00266 //! Default IP address for this host.
00267 #define DEFAULT_IP_ADDR         ( IP_ADDRESS(10, 0, 0, 2) )
00268 //! Default IP netmask for this host.
00269 #define DEFAULT_NETMASK_ADDR    ( IP_ADDRESS(255, 0, 0, 0) )
00270 //! \brief
00271 //!     This is the "ifconfig" command for the shell.
00272 //! \param cmd A string of command parameters.
00273 void ifconfig(char *cmd)
00274 {
00275         uint8_t ip_dot[STR_MAX_LENGTH];
00276         in_addr_t ip, netmask;
00277 
00278         // Skip initial spaces into the parameters string               //
00279         while (*cmd == ' ') cmd++;
00280         if (*cmd == '\0')
00281         {
00282                 // Simply print current ethernet configuration          //
00283                 rtl8139_dump_info(rtl);
00284                 return;
00285         }
00286         if ( strstr(cmd, "up") )
00287         {
00288                 if ( rtl != NULL )
00289                 {
00290                         kprintf("\n\rRTL8139 is already up!");
00291                         if ( strstr(cmd, "promisc") )
00292                                 rtl8139_promisc(get_rtl8139_device(), TRUE);
00293                         else
00294                                 rtl8139_promisc(get_rtl8139_device(), FALSE);
00295                         kprintf("\n\rRTL8139: promiscuous mode %s\n\r",
00296                                 (get_rtl8139_device()->promisc) ? "ENABLED" : "DISABLED");
00297                         return;
00298                 }
00299 
00300                 // Get the host IP and netmask                          //
00301                 kprintf("\n\rIP address: ");
00302                 gets(ip_dot);
00303                 if ( !inet_aton(ip_dot, &ip) )
00304                 {
00305                         // Set the IP to default value                  //
00306                         ip = DEFAULT_IP_ADDR;
00307                 }
00308                 kprintf("\rNetmask   : ");
00309                 gets(ip_dot);
00310                 if ( !inet_aton(ip_dot, &netmask) )
00311                 {
00312                         // Set the netmask to default value             //
00313                         netmask = DEFAULT_NETMASK_ADDR;
00314                 }
00315 
00316                 // Set the host ip and netmask addresses                //
00317                 set_host_ip_net(ip, netmask);
00318                 // Initialize the ethernet buffer                       //
00319                 eth_init_buffer();
00320                 // Reset the ARP cache                                  //
00321                 arp_reset_cache();
00322 
00323                 // Open the TCP module                                  //
00324                 tcp_module_init();
00325 
00326                 // Initialize the RTL8139 device                        //
00327                 switch( rtl8139_init(strstr(cmd, "promisc") ? TRUE : FALSE) )
00328                 {
00329                         case ( 0 ):
00330                         // --- SUCCESS ---                              //
00331                         // Dump the ethernet card informations          //
00332                         rtl8139_dump_info(rtl);
00333                         // Create the ethernet receiver thread          //
00334                         eth_recv_thread1 =
00335                                 create_process(
00336                                         &eth_recv_daemon, &eth_recv_daemon,
00337                                         0, "eth_recvd1", KERNEL_PRIVILEGE);
00338                         eth_recv_thread2 =
00339                                 create_process(
00340                                         &eth_recv_daemon, &eth_recv_daemon,
00341                                         0, "eth_recvd2", KERNEL_PRIVILEGE);
00342                         break;
00343 
00344                         case ( -ENXIO ):
00345                         // --- DEVICE NOT FOUND ---                     //
00346                         // Null the host ip and netmask                 //
00347                         set_host_ip_net(0, 0);
00348                         // Destroy the ethernet buffer                  //
00349                         kfree( eth_recv_buf );
00350                         // Print the error message                      //
00351                         kprintf("\n\rRTL8139: cannot find an ethernet card!\n\r");
00352                         break;
00353 
00354                         case ( -EIO ):
00355                         // --- I/O ERROR ---                            //
00356                         // Null the host ip and netmask                 //
00357                         set_host_ip_net(0, 0);
00358                         // Destroy the ethernet buffer                  //
00359                         kfree( eth_recv_buf );
00360                         // Print the error message                      //
00361                         kprintf("\n\rRTL8139: I/O error!\n\r");
00362                         break;
00363                 }
00364                 return;
00365         }
00366         if ( strstr(cmd, "down") )
00367         {
00368                 kprintf("\n\rRTL8139: shutting down eth0 device...");
00369 
00370                 // Close the TCP module                                 //
00371                 tcp_module_close();
00372 
00373                 // Destroy the ethernet buffer                          //
00374                 kfree( eth_recv_buf );
00375                 // Kill the ethernet receiver thread                    //
00376                 kill(eth_recv_thread1->pid);
00377                 kill(eth_recv_thread2->pid);
00378                 // Reset the ARP cache                                  //
00379                 arp_reset_cache();
00380                 // Close the RTL8139 interface                          //
00381                 rtl8139_close(&rtl);
00382                 kprintf("\n\r");
00383                 return;
00384         }
00385 
00386         // Command unknown!                                             //
00387         kprintf("\n\rerror: %s unknown!\n\r", cmd);
00388 }

Generated on Fri Feb 20 15:32:15 2004 for Minirighi by doxygen1.2.18