netdevice.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <byteswap.h>
00025 #include <string.h>
00026 #include <errno.h>
00027 #include <gpxe/if_ether.h>
00028 #include <gpxe/iobuf.h>
00029 #include <gpxe/tables.h>
00030 #include <gpxe/process.h>
00031 #include <gpxe/init.h>
00032 #include <gpxe/device.h>
00033 #include <gpxe/errortab.h>
00034 #include <gpxe/netdevice.h>
00035 
00036 /** @file
00037  *
00038  * Network device management
00039  *
00040  */
00041 
00042 /** List of network devices */
00043 struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
00044 
00045 /** List of open network devices, in reverse order of opening */
00046 static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
00047 
00048 /** Default link status code */
00049 #define EUNKNOWN_LINK_STATUS EINPROGRESS
00050 
00051 /** Human-readable message for the default link status */
00052 struct errortab netdev_errors[] __errortab = {
00053         { EUNKNOWN_LINK_STATUS, "Unknown" },
00054 };
00055 
00056 /**
00057  * Mark network device as having link down
00058  *
00059  * @v netdev            Network device
00060  */
00061 void netdev_link_down ( struct net_device *netdev ) {
00062 
00063         switch ( netdev->link_rc ) {
00064         case 0:
00065         case -EUNKNOWN_LINK_STATUS:
00066                 netdev->link_rc = -ENOTCONN;
00067                 break;
00068         default:
00069                 /* Avoid clobbering a more detailed link status code,
00070                  * if one is already set.
00071                  */
00072                 break;
00073         }
00074 }
00075 
00076 /**
00077  * Record network device statistic
00078  *
00079  * @v stats             Network device statistics
00080  * @v rc                Status code
00081  */
00082 static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
00083         struct net_device_error *error;
00084         struct net_device_error *least_common_error;
00085         unsigned int i;
00086 
00087         /* If this is not an error, just update the good counter */
00088         if ( rc == 0 ) {
00089                 stats->good++;
00090                 return;
00091         }
00092 
00093         /* Update the bad counter */
00094         stats->bad++;
00095 
00096         /* Locate the appropriate error record */
00097         least_common_error = &stats->errors[0];
00098         for ( i = 0 ; i < ( sizeof ( stats->errors ) /
00099                             sizeof ( stats->errors[0] ) ) ; i++ ) {
00100                 error = &stats->errors[i];
00101                 /* Update matching record, if found */
00102                 if ( error->rc == rc ) {
00103                         error->count++;
00104                         return;
00105                 }
00106                 if ( error->count < least_common_error->count )
00107                         least_common_error = error;
00108         }
00109 
00110         /* Overwrite the least common error record */
00111         least_common_error->rc = rc;
00112         least_common_error->count = 1;
00113 }
00114 
00115 /**
00116  * Transmit raw packet via network device
00117  *
00118  * @v netdev            Network device
00119  * @v iobuf             I/O buffer
00120  * @ret rc              Return status code
00121  *
00122  * Transmits the packet via the specified network device.  This
00123  * function takes ownership of the I/O buffer.
00124  */
00125 int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
00126         int rc;
00127 
00128         DBGC ( netdev, "NETDEV %p transmitting %p (%p+%zx)\n",
00129                netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
00130 
00131         list_add_tail ( &iobuf->list, &netdev->tx_queue );
00132 
00133         if ( ! netdev_is_open ( netdev ) ) {
00134                 rc = -ENETUNREACH;
00135                 goto err;
00136         }
00137                 
00138         if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 )
00139                 goto err;
00140 
00141         return 0;
00142 
00143  err:
00144         netdev_tx_complete_err ( netdev, iobuf, rc );
00145         return rc;
00146 }
00147 
00148 /**
00149  * Complete network transmission
00150  *
00151  * @v netdev            Network device
00152  * @v iobuf             I/O buffer
00153  * @v rc                Packet status code
00154  *
00155  * The packet must currently be in the network device's TX queue.
00156  */
00157 void netdev_tx_complete_err ( struct net_device *netdev,
00158                               struct io_buffer *iobuf, int rc ) {
00159 
00160         /* Update statistics counter */
00161         netdev_record_stat ( &netdev->tx_stats, rc );
00162         if ( rc == 0 ) {
00163                 DBGC ( netdev, "NETDEV %p transmission %p complete\n",
00164                        netdev, iobuf );
00165         } else {
00166                 DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
00167                        netdev, iobuf, strerror ( rc ) );
00168         }
00169 
00170         /* Catch data corruption as early as possible */
00171         assert ( iobuf->list.next != NULL );
00172         assert ( iobuf->list.prev != NULL );
00173 
00174         /* Dequeue and free I/O buffer */
00175         list_del ( &iobuf->list );
00176         free_iob ( iobuf );
00177 }
00178 
00179 /**
00180  * Complete network transmission
00181  *
00182  * @v netdev            Network device
00183  * @v rc                Packet status code
00184  *
00185  * Completes the oldest outstanding packet in the TX queue.
00186  */
00187 void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) {
00188         struct io_buffer *iobuf;
00189 
00190         list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
00191                 netdev_tx_complete_err ( netdev, iobuf, rc );
00192                 return;
00193         }
00194 }
00195 
00196 /**
00197  * Flush device's transmit queue
00198  *
00199  * @v netdev            Network device
00200  */
00201 static void netdev_tx_flush ( struct net_device *netdev ) {
00202 
00203         /* Discard any packets in the TX queue */
00204         while ( ! list_empty ( &netdev->tx_queue ) ) {
00205                 netdev_tx_complete_next_err ( netdev, -ECANCELED );
00206         }
00207 }
00208 
00209 /**
00210  * Add packet to receive queue
00211  *
00212  * @v netdev            Network device
00213  * @v iobuf             I/O buffer, or NULL
00214  *
00215  * The packet is added to the network device's RX queue.  This
00216  * function takes ownership of the I/O buffer.
00217  */
00218 void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
00219 
00220         DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
00221                netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
00222 
00223         /* Enqueue packet */
00224         list_add_tail ( &iobuf->list, &netdev->rx_queue );
00225 
00226         /* Update statistics counter */
00227         netdev_record_stat ( &netdev->rx_stats, 0 );
00228 }
00229 
00230 /**
00231  * Discard received packet
00232  *
00233  * @v netdev            Network device
00234  * @v iobuf             I/O buffer, or NULL
00235  * @v rc                Packet status code
00236  *
00237  * The packet is discarded and an RX error is recorded.  This function
00238  * takes ownership of the I/O buffer.  @c iobuf may be NULL if, for
00239  * example, the net device wishes to report an error due to being
00240  * unable to allocate an I/O buffer.
00241  */
00242 void netdev_rx_err ( struct net_device *netdev,
00243                      struct io_buffer *iobuf, int rc ) {
00244 
00245         DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n",
00246                netdev, iobuf, strerror ( rc ) );
00247 
00248         /* Discard packet */
00249         free_iob ( iobuf );
00250 
00251         /* Update statistics counter */
00252         netdev_record_stat ( &netdev->rx_stats, rc );
00253 }
00254 
00255 /**
00256  * Poll for completed and received packets on network device
00257  *
00258  * @v netdev            Network device
00259  *
00260  * Polls the network device for completed transmissions and received
00261  * packets.  Any received packets will be added to the RX packet queue
00262  * via netdev_rx().
00263  */
00264 void netdev_poll ( struct net_device *netdev ) {
00265 
00266         if ( netdev_is_open ( netdev ) )
00267                 netdev->op->poll ( netdev );
00268 }
00269 
00270 /**
00271  * Remove packet from device's receive queue
00272  *
00273  * @v netdev            Network device
00274  * @ret iobuf           I/O buffer, or NULL
00275  *
00276  * Removes the first packet from the device's RX queue and returns it.
00277  * Ownership of the packet is transferred to the caller.
00278  */
00279 struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) {
00280         struct io_buffer *iobuf;
00281 
00282         list_for_each_entry ( iobuf, &netdev->rx_queue, list ) {
00283                 list_del ( &iobuf->list );
00284                 return iobuf;
00285         }
00286         return NULL;
00287 }
00288 
00289 /**
00290  * Flush device's receive queue
00291  *
00292  * @v netdev            Network device
00293  */
00294 static void netdev_rx_flush ( struct net_device *netdev ) {
00295         struct io_buffer *iobuf;
00296 
00297         /* Discard any packets in the RX queue */
00298         while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
00299                 netdev_rx_err ( netdev, iobuf, -ECANCELED );
00300         }
00301 }
00302 
00303 /**
00304  * Free network device
00305  *
00306  * @v refcnt            Network device reference counter
00307  */
00308 static void free_netdev ( struct refcnt *refcnt ) {
00309         struct net_device *netdev =
00310                 container_of ( refcnt, struct net_device, refcnt );
00311         
00312         netdev_tx_flush ( netdev );
00313         netdev_rx_flush ( netdev );
00314         clear_settings ( netdev_settings ( netdev ) );
00315         free ( netdev );
00316 }
00317 
00318 /**
00319  * Allocate network device
00320  *
00321  * @v priv_size         Size of private data area (net_device::priv)
00322  * @ret netdev          Network device, or NULL
00323  *
00324  * Allocates space for a network device and its private data area.
00325  */
00326 struct net_device * alloc_netdev ( size_t priv_size ) {
00327         struct net_device *netdev;
00328         size_t total_len;
00329 
00330         total_len = ( sizeof ( *netdev ) + priv_size );
00331         netdev = zalloc ( total_len );
00332         if ( netdev ) {
00333                 netdev->refcnt.free = free_netdev;
00334                 netdev->link_rc = -EUNKNOWN_LINK_STATUS;
00335                 INIT_LIST_HEAD ( &netdev->tx_queue );
00336                 INIT_LIST_HEAD ( &netdev->rx_queue );
00337                 netdev_settings_init ( netdev );
00338                 netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
00339         }
00340         return netdev;
00341 }
00342 
00343 /**
00344  * Register network device
00345  *
00346  * @v netdev            Network device
00347  * @ret rc              Return status code
00348  *
00349  * Gives the network device a name and adds it to the list of network
00350  * devices.
00351  */
00352 int register_netdev ( struct net_device *netdev ) {
00353         static unsigned int ifindex = 0;
00354         int rc;
00355 
00356         /* Create device name */
00357         snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
00358                    ifindex++ );
00359 
00360         /* Set initial link-layer address */
00361         netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
00362 
00363         /* Register per-netdev configuration settings */
00364         if ( ( rc = register_settings ( netdev_settings ( netdev ),
00365                                         NULL ) ) != 0 ) {
00366                 DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
00367                        netdev, strerror ( rc ) );
00368                 return rc;
00369         }
00370 
00371         /* Add to device list */
00372         netdev_get ( netdev );
00373         list_add_tail ( &netdev->list, &net_devices );
00374         DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n",
00375                netdev, netdev->name, netdev->dev->name,
00376                netdev_addr ( netdev ) );
00377 
00378         return 0;
00379 }
00380 
00381 /**
00382  * Open network device
00383  *
00384  * @v netdev            Network device
00385  * @ret rc              Return status code
00386  */
00387 int netdev_open ( struct net_device *netdev ) {
00388         int rc;
00389 
00390         /* Do nothing if device is already open */
00391         if ( netdev->state & NETDEV_OPEN )
00392                 return 0;
00393 
00394         DBGC ( netdev, "NETDEV %p opening\n", netdev );
00395 
00396         /* Open the device */
00397         if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
00398                 return rc;
00399 
00400         /* Mark as opened */
00401         netdev->state |= NETDEV_OPEN;
00402 
00403         /* Add to head of open devices list */
00404         list_add ( &netdev->open_list, &open_net_devices );
00405 
00406         return 0;
00407 }
00408 
00409 /**
00410  * Close network device
00411  *
00412  * @v netdev            Network device
00413  */
00414 void netdev_close ( struct net_device *netdev ) {
00415 
00416         /* Do nothing if device is already closed */
00417         if ( ! ( netdev->state & NETDEV_OPEN ) )
00418                 return;
00419 
00420         DBGC ( netdev, "NETDEV %p closing\n", netdev );
00421 
00422         /* Close the device */
00423         netdev->op->close ( netdev );
00424 
00425         /* Flush TX and RX queues */
00426         netdev_tx_flush ( netdev );
00427         netdev_rx_flush ( netdev );
00428 
00429         /* Mark as closed */
00430         netdev->state &= ~NETDEV_OPEN;
00431 
00432         /* Remove from open devices list */
00433         list_del ( &netdev->open_list );
00434 }
00435 
00436 /**
00437  * Unregister network device
00438  *
00439  * @v netdev            Network device
00440  *
00441  * Removes the network device from the list of network devices.
00442  */
00443 void unregister_netdev ( struct net_device *netdev ) {
00444 
00445         /* Ensure device is closed */
00446         netdev_close ( netdev );
00447 
00448         /* Unregister per-netdev configuration settings */
00449         unregister_settings ( netdev_settings ( netdev ) );
00450 
00451         /* Remove from device list */
00452         list_del ( &netdev->list );
00453         netdev_put ( netdev );
00454         DBGC ( netdev, "NETDEV %p unregistered\n", netdev );
00455 }
00456 
00457 /** Enable or disable interrupts
00458  *
00459  * @v netdev            Network device
00460  * @v enable            Interrupts should be enabled
00461  */
00462 void netdev_irq ( struct net_device *netdev, int enable ) {
00463 
00464         /* Enable or disable device interrupts */
00465         netdev->op->irq ( netdev, enable );
00466 
00467         /* Record interrupt enabled state */
00468         netdev->state &= ~NETDEV_IRQ_ENABLED;
00469         if ( enable )
00470                 netdev->state |= NETDEV_IRQ_ENABLED;
00471 }
00472 
00473 /**
00474  * Get network device by name
00475  *
00476  * @v name              Network device name
00477  * @ret netdev          Network device, or NULL
00478  */
00479 struct net_device * find_netdev ( const char *name ) {
00480         struct net_device *netdev;
00481 
00482         list_for_each_entry ( netdev, &net_devices, list ) {
00483                 if ( strcmp ( netdev->name, name ) == 0 )
00484                         return netdev;
00485         }
00486 
00487         return NULL;
00488 }
00489 
00490 /**
00491  * Get network device by PCI bus:dev.fn address
00492  *
00493  * @v bus_type          Bus type
00494  * @v location          Bus location
00495  * @ret netdev          Network device, or NULL
00496  */
00497 struct net_device * find_netdev_by_location ( unsigned int bus_type,
00498                                               unsigned int location ) {
00499         struct net_device *netdev;
00500 
00501         list_for_each_entry ( netdev, &net_devices, list ) {
00502                 if ( ( netdev->dev->desc.bus_type == bus_type ) &&
00503                      ( netdev->dev->desc.location == location ) )
00504                         return netdev;
00505         }
00506 
00507         return NULL;    
00508 }
00509 
00510 /**
00511  * Get most recently opened network device
00512  *
00513  * @ret netdev          Most recently opened network device, or NULL
00514  */
00515 struct net_device * last_opened_netdev ( void ) {
00516         struct net_device *netdev;
00517 
00518         list_for_each_entry ( netdev, &open_net_devices, open_list ) {
00519                 assert ( netdev_is_open ( netdev ) );
00520                 return netdev;
00521         }
00522 
00523         return NULL;
00524 }
00525 
00526 /**
00527  * Transmit network-layer packet
00528  *
00529  * @v iobuf             I/O buffer
00530  * @v netdev            Network device
00531  * @v net_protocol      Network-layer protocol
00532  * @v ll_dest           Destination link-layer address
00533  * @ret rc              Return status code
00534  *
00535  * Prepends link-layer headers to the I/O buffer and transmits the
00536  * packet via the specified network device.  This function takes
00537  * ownership of the I/O buffer.
00538  */
00539 int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
00540              struct net_protocol *net_protocol, const void *ll_dest ) {
00541         struct ll_protocol *ll_protocol = netdev->ll_protocol;
00542         int rc;
00543 
00544         /* Force a poll on the netdevice to (potentially) clear any
00545          * backed-up TX completions.  This is needed on some network
00546          * devices to avoid excessive losses due to small TX ring
00547          * sizes.
00548          */
00549         netdev_poll ( netdev );
00550 
00551         /* Add link-layer header */
00552         if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, netdev->ll_addr,
00553                                         net_protocol->net_proto ) ) != 0 ) {
00554                 free_iob ( iobuf );
00555                 return rc;
00556         }
00557 
00558         /* Transmit packet */
00559         return netdev_tx ( netdev, iobuf );
00560 }
00561 
00562 /**
00563  * Process received network-layer packet
00564  *
00565  * @v iobuf             I/O buffer
00566  * @v netdev            Network device
00567  * @v net_proto         Network-layer protocol, in network-byte order
00568  * @v ll_source         Source link-layer address
00569  * @ret rc              Return status code
00570  */
00571 int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
00572              uint16_t net_proto, const void *ll_source ) {
00573         struct net_protocol *net_protocol;
00574 
00575         /* Hand off to network-layer protocol, if any */
00576         for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
00577                 if ( net_protocol->net_proto == net_proto )
00578                         return net_protocol->rx ( iobuf, netdev, ll_source );
00579         }
00580 
00581         DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n",
00582                netdev, ntohs ( net_proto ) );
00583         free_iob ( iobuf );
00584         return 0;
00585 }
00586 
00587 /**
00588  * Single-step the network stack
00589  *
00590  * @v process           Network stack process
00591  *
00592  * This polls all interfaces for received packets, and processes
00593  * packets from the RX queue.
00594  */
00595 static void net_step ( struct process *process __unused ) {
00596         struct net_device *netdev;
00597         struct io_buffer *iobuf;
00598         struct ll_protocol *ll_protocol;
00599         const void *ll_dest;
00600         const void *ll_source;
00601         uint16_t net_proto;
00602         int rc;
00603 
00604         /* Poll and process each network device */
00605         list_for_each_entry ( netdev, &net_devices, list ) {
00606 
00607                 /* Poll for new packets */
00608                 netdev_poll ( netdev );
00609 
00610                 /* Process at most one received packet.  Give priority
00611                  * to getting packets out of the NIC over processing
00612                  * the received packets, because we advertise a window
00613                  * that assumes that we can receive packets from the
00614                  * NIC faster than they arrive.
00615                  */
00616                 if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
00617 
00618                         DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n",
00619                                netdev, iobuf, iobuf->data,
00620                                iob_len ( iobuf ) );
00621 
00622                         /* Remove link-layer header */
00623                         ll_protocol = netdev->ll_protocol;
00624                         if ( ( rc = ll_protocol->pull ( netdev, iobuf,
00625                                                         &ll_dest, &ll_source,
00626                                                         &net_proto ) ) != 0 ) {
00627                                 free_iob ( iobuf );
00628                                 continue;
00629                         }
00630 
00631                         net_rx ( iobuf, netdev, net_proto, ll_source );
00632                 }
00633         }
00634 }
00635 
00636 /** Networking stack process */
00637 struct process net_process __permanent_process = {
00638         .list = LIST_HEAD_INIT ( net_process.list ),
00639         .step = net_step,
00640 };

Generated on Tue Apr 6 20:01:10 2010 for gPXE by  doxygen 1.5.7.1