|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2006 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdint.h> ! 22: #include <stdlib.h> ! 23: #include <stdio.h> ! 24: #include <byteswap.h> ! 25: #include <string.h> ! 26: #include <errno.h> ! 27: #include <config/general.h> ! 28: #include <ipxe/if_ether.h> ! 29: #include <ipxe/iobuf.h> ! 30: #include <ipxe/tables.h> ! 31: #include <ipxe/process.h> ! 32: #include <ipxe/init.h> ! 33: #include <ipxe/device.h> ! 34: #include <ipxe/errortab.h> ! 35: #include <ipxe/netdevice.h> ! 36: ! 37: /** @file ! 38: * ! 39: * Network device management ! 40: * ! 41: */ ! 42: ! 43: /** List of network devices */ ! 44: struct list_head net_devices = LIST_HEAD_INIT ( net_devices ); ! 45: ! 46: /** List of open network devices, in reverse order of opening */ ! 47: static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices ); ! 48: ! 49: /** Default unknown link status code */ ! 50: #define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS ) ! 51: #define EINFO_EUNKNOWN_LINK_STATUS \ ! 52: __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" ) ! 53: ! 54: /** Default link-down status code */ ! 55: #define ENOTCONN_LINK_DOWN __einfo_error ( EINFO_ENOTCONN_LINK_DOWN ) ! 56: #define EINFO_ENOTCONN_LINK_DOWN \ ! 57: __einfo_uniqify ( EINFO_ENOTCONN, 0x01, "Down" ) ! 58: ! 59: /** Human-readable message for the default link statuses */ ! 60: struct errortab netdev_errors[] __errortab = { ! 61: __einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ), ! 62: __einfo_errortab ( EINFO_ENOTCONN_LINK_DOWN ), ! 63: }; ! 64: ! 65: /** ! 66: * Notify drivers of network device or link state change ! 67: * ! 68: * @v netdev Network device ! 69: */ ! 70: static void netdev_notify ( struct net_device *netdev ) { ! 71: struct net_driver *driver; ! 72: ! 73: for_each_table_entry ( driver, NET_DRIVERS ) ! 74: driver->notify ( netdev ); ! 75: } ! 76: ! 77: /** ! 78: * Mark network device as having a specific link state ! 79: * ! 80: * @v netdev Network device ! 81: * @v rc Link status code ! 82: */ ! 83: void netdev_link_err ( struct net_device *netdev, int rc ) { ! 84: ! 85: /* Record link state */ ! 86: netdev->link_rc = rc; ! 87: if ( netdev->link_rc == 0 ) { ! 88: DBGC ( netdev, "NETDEV %s link is up\n", netdev->name ); ! 89: } else { ! 90: DBGC ( netdev, "NETDEV %s link is down: %s\n", ! 91: netdev->name, strerror ( netdev->link_rc ) ); ! 92: } ! 93: ! 94: /* Notify drivers of link state change */ ! 95: netdev_notify ( netdev ); ! 96: } ! 97: ! 98: /** ! 99: * Mark network device as having link down ! 100: * ! 101: * @v netdev Network device ! 102: */ ! 103: void netdev_link_down ( struct net_device *netdev ) { ! 104: ! 105: /* Avoid clobbering a more detailed link status code, if one ! 106: * is already set. ! 107: */ ! 108: if ( ( netdev->link_rc == 0 ) || ! 109: ( netdev->link_rc == -EUNKNOWN_LINK_STATUS ) ) { ! 110: netdev_link_err ( netdev, -ENOTCONN_LINK_DOWN ); ! 111: } ! 112: } ! 113: ! 114: /** ! 115: * Record network device statistic ! 116: * ! 117: * @v stats Network device statistics ! 118: * @v rc Status code ! 119: */ ! 120: static void netdev_record_stat ( struct net_device_stats *stats, int rc ) { ! 121: struct net_device_error *error; ! 122: struct net_device_error *least_common_error; ! 123: unsigned int i; ! 124: ! 125: /* If this is not an error, just update the good counter */ ! 126: if ( rc == 0 ) { ! 127: stats->good++; ! 128: return; ! 129: } ! 130: ! 131: /* Update the bad counter */ ! 132: stats->bad++; ! 133: ! 134: /* Locate the appropriate error record */ ! 135: least_common_error = &stats->errors[0]; ! 136: for ( i = 0 ; i < ( sizeof ( stats->errors ) / ! 137: sizeof ( stats->errors[0] ) ) ; i++ ) { ! 138: error = &stats->errors[i]; ! 139: /* Update matching record, if found */ ! 140: if ( error->rc == rc ) { ! 141: error->count++; ! 142: return; ! 143: } ! 144: if ( error->count < least_common_error->count ) ! 145: least_common_error = error; ! 146: } ! 147: ! 148: /* Overwrite the least common error record */ ! 149: least_common_error->rc = rc; ! 150: least_common_error->count = 1; ! 151: } ! 152: ! 153: /** ! 154: * Transmit raw packet via network device ! 155: * ! 156: * @v netdev Network device ! 157: * @v iobuf I/O buffer ! 158: * @ret rc Return status code ! 159: * ! 160: * Transmits the packet via the specified network device. This ! 161: * function takes ownership of the I/O buffer. ! 162: */ ! 163: int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { ! 164: int rc; ! 165: ! 166: DBGC ( netdev, "NETDEV %s transmitting %p (%p+%zx)\n", ! 167: netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) ); ! 168: ! 169: /* Enqueue packet */ ! 170: list_add_tail ( &iobuf->list, &netdev->tx_queue ); ! 171: ! 172: /* Avoid calling transmit() on unopened network devices */ ! 173: if ( ! netdev_is_open ( netdev ) ) { ! 174: rc = -ENETUNREACH; ! 175: goto err; ! 176: } ! 177: ! 178: /* Discard packet (for test purposes) if applicable */ ! 179: if ( ( NETDEV_DISCARD_RATE > 0 ) && ! 180: ( ( random() % NETDEV_DISCARD_RATE ) == 0 ) ) { ! 181: rc = -EAGAIN; ! 182: goto err; ! 183: } ! 184: ! 185: /* Transmit packet */ ! 186: if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) ! 187: goto err; ! 188: ! 189: return 0; ! 190: ! 191: err: ! 192: netdev_tx_complete_err ( netdev, iobuf, rc ); ! 193: return rc; ! 194: } ! 195: ! 196: /** ! 197: * Complete network transmission ! 198: * ! 199: * @v netdev Network device ! 200: * @v iobuf I/O buffer ! 201: * @v rc Packet status code ! 202: * ! 203: * The packet must currently be in the network device's TX queue. ! 204: */ ! 205: void netdev_tx_complete_err ( struct net_device *netdev, ! 206: struct io_buffer *iobuf, int rc ) { ! 207: ! 208: /* Update statistics counter */ ! 209: netdev_record_stat ( &netdev->tx_stats, rc ); ! 210: if ( rc == 0 ) { ! 211: DBGC ( netdev, "NETDEV %s transmission %p complete\n", ! 212: netdev->name, iobuf ); ! 213: } else { ! 214: DBGC ( netdev, "NETDEV %s transmission %p failed: %s\n", ! 215: netdev->name, iobuf, strerror ( rc ) ); ! 216: } ! 217: ! 218: /* Catch data corruption as early as possible */ ! 219: assert ( iobuf->list.next != NULL ); ! 220: assert ( iobuf->list.prev != NULL ); ! 221: ! 222: /* Dequeue and free I/O buffer */ ! 223: list_del ( &iobuf->list ); ! 224: free_iob ( iobuf ); ! 225: } ! 226: ! 227: /** ! 228: * Complete network transmission ! 229: * ! 230: * @v netdev Network device ! 231: * @v rc Packet status code ! 232: * ! 233: * Completes the oldest outstanding packet in the TX queue. ! 234: */ ! 235: void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) { ! 236: struct io_buffer *iobuf; ! 237: ! 238: list_for_each_entry ( iobuf, &netdev->tx_queue, list ) { ! 239: netdev_tx_complete_err ( netdev, iobuf, rc ); ! 240: return; ! 241: } ! 242: } ! 243: ! 244: /** ! 245: * Flush device's transmit queue ! 246: * ! 247: * @v netdev Network device ! 248: */ ! 249: static void netdev_tx_flush ( struct net_device *netdev ) { ! 250: ! 251: /* Discard any packets in the TX queue */ ! 252: while ( ! list_empty ( &netdev->tx_queue ) ) { ! 253: netdev_tx_complete_next_err ( netdev, -ECANCELED ); ! 254: } ! 255: } ! 256: ! 257: /** ! 258: * Add packet to receive queue ! 259: * ! 260: * @v netdev Network device ! 261: * @v iobuf I/O buffer, or NULL ! 262: * ! 263: * The packet is added to the network device's RX queue. This ! 264: * function takes ownership of the I/O buffer. ! 265: */ ! 266: void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { ! 267: ! 268: DBGC ( netdev, "NETDEV %s received %p (%p+%zx)\n", ! 269: netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) ); ! 270: ! 271: /* Discard packet (for test purposes) if applicable */ ! 272: if ( ( NETDEV_DISCARD_RATE > 0 ) && ! 273: ( ( random() % NETDEV_DISCARD_RATE ) == 0 ) ) { ! 274: netdev_rx_err ( netdev, iobuf, -EAGAIN ); ! 275: return; ! 276: } ! 277: ! 278: /* Enqueue packet */ ! 279: list_add_tail ( &iobuf->list, &netdev->rx_queue ); ! 280: ! 281: /* Update statistics counter */ ! 282: netdev_record_stat ( &netdev->rx_stats, 0 ); ! 283: } ! 284: ! 285: /** ! 286: * Discard received packet ! 287: * ! 288: * @v netdev Network device ! 289: * @v iobuf I/O buffer, or NULL ! 290: * @v rc Packet status code ! 291: * ! 292: * The packet is discarded and an RX error is recorded. This function ! 293: * takes ownership of the I/O buffer. @c iobuf may be NULL if, for ! 294: * example, the net device wishes to report an error due to being ! 295: * unable to allocate an I/O buffer. ! 296: */ ! 297: void netdev_rx_err ( struct net_device *netdev, ! 298: struct io_buffer *iobuf, int rc ) { ! 299: ! 300: DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n", ! 301: netdev->name, iobuf, strerror ( rc ) ); ! 302: ! 303: /* Discard packet */ ! 304: free_iob ( iobuf ); ! 305: ! 306: /* Update statistics counter */ ! 307: netdev_record_stat ( &netdev->rx_stats, rc ); ! 308: } ! 309: ! 310: /** ! 311: * Poll for completed and received packets on network device ! 312: * ! 313: * @v netdev Network device ! 314: * ! 315: * Polls the network device for completed transmissions and received ! 316: * packets. Any received packets will be added to the RX packet queue ! 317: * via netdev_rx(). ! 318: */ ! 319: void netdev_poll ( struct net_device *netdev ) { ! 320: ! 321: if ( netdev_is_open ( netdev ) ) ! 322: netdev->op->poll ( netdev ); ! 323: } ! 324: ! 325: /** ! 326: * Remove packet from device's receive queue ! 327: * ! 328: * @v netdev Network device ! 329: * @ret iobuf I/O buffer, or NULL ! 330: * ! 331: * Removes the first packet from the device's RX queue and returns it. ! 332: * Ownership of the packet is transferred to the caller. ! 333: */ ! 334: struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) { ! 335: struct io_buffer *iobuf; ! 336: ! 337: iobuf = list_first_entry ( &netdev->rx_queue, struct io_buffer, list ); ! 338: if ( ! iobuf ) ! 339: return NULL; ! 340: ! 341: list_del ( &iobuf->list ); ! 342: return iobuf; ! 343: } ! 344: ! 345: /** ! 346: * Flush device's receive queue ! 347: * ! 348: * @v netdev Network device ! 349: */ ! 350: static void netdev_rx_flush ( struct net_device *netdev ) { ! 351: struct io_buffer *iobuf; ! 352: ! 353: /* Discard any packets in the RX queue */ ! 354: while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) { ! 355: netdev_rx_err ( netdev, iobuf, -ECANCELED ); ! 356: } ! 357: } ! 358: ! 359: /** ! 360: * Free network device ! 361: * ! 362: * @v refcnt Network device reference counter ! 363: */ ! 364: static void free_netdev ( struct refcnt *refcnt ) { ! 365: struct net_device *netdev = ! 366: container_of ( refcnt, struct net_device, refcnt ); ! 367: ! 368: netdev_tx_flush ( netdev ); ! 369: netdev_rx_flush ( netdev ); ! 370: clear_settings ( netdev_settings ( netdev ) ); ! 371: free ( netdev ); ! 372: } ! 373: ! 374: /** ! 375: * Allocate network device ! 376: * ! 377: * @v priv_size Size of private data area (net_device::priv) ! 378: * @ret netdev Network device, or NULL ! 379: * ! 380: * Allocates space for a network device and its private data area. ! 381: */ ! 382: struct net_device * alloc_netdev ( size_t priv_size ) { ! 383: struct net_device *netdev; ! 384: size_t total_len; ! 385: ! 386: total_len = ( sizeof ( *netdev ) + priv_size ); ! 387: netdev = zalloc ( total_len ); ! 388: if ( netdev ) { ! 389: ref_init ( &netdev->refcnt, free_netdev ); ! 390: netdev->link_rc = -EUNKNOWN_LINK_STATUS; ! 391: INIT_LIST_HEAD ( &netdev->tx_queue ); ! 392: INIT_LIST_HEAD ( &netdev->rx_queue ); ! 393: netdev_settings_init ( netdev ); ! 394: netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) ); ! 395: } ! 396: return netdev; ! 397: } ! 398: ! 399: /** ! 400: * Register network device ! 401: * ! 402: * @v netdev Network device ! 403: * @ret rc Return status code ! 404: * ! 405: * Gives the network device a name and adds it to the list of network ! 406: * devices. ! 407: */ ! 408: int register_netdev ( struct net_device *netdev ) { ! 409: static unsigned int ifindex = 0; ! 410: struct net_driver *driver; ! 411: int rc; ! 412: ! 413: /* Create device name */ ! 414: if ( netdev->name[0] == '\0' ) { ! 415: snprintf ( netdev->name, sizeof ( netdev->name ), "net%d", ! 416: ifindex++ ); ! 417: } ! 418: ! 419: /* Set initial link-layer address */ ! 420: netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); ! 421: ! 422: /* Add to device list */ ! 423: netdev_get ( netdev ); ! 424: list_add_tail ( &netdev->list, &net_devices ); ! 425: DBGC ( netdev, "NETDEV %s registered (phys %s hwaddr %s)\n", ! 426: netdev->name, netdev->dev->name, ! 427: netdev_addr ( netdev ) ); ! 428: ! 429: /* Register per-netdev configuration settings */ ! 430: if ( ( rc = register_settings ( netdev_settings ( netdev ), ! 431: NULL, netdev->name ) ) != 0 ) { ! 432: DBGC ( netdev, "NETDEV %s could not register settings: %s\n", ! 433: netdev->name, strerror ( rc ) ); ! 434: goto err_register_settings; ! 435: } ! 436: ! 437: /* Probe device */ ! 438: for_each_table_entry ( driver, NET_DRIVERS ) { ! 439: if ( ( rc = driver->probe ( netdev ) ) != 0 ) { ! 440: DBGC ( netdev, "NETDEV %s could not add %s device: " ! 441: "%s\n", netdev->name, driver->name, ! 442: strerror ( rc ) ); ! 443: goto err_probe; ! 444: } ! 445: } ! 446: ! 447: return 0; ! 448: ! 449: err_probe: ! 450: for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) ! 451: driver->remove ( netdev ); ! 452: unregister_settings ( netdev_settings ( netdev ) ); ! 453: err_register_settings: ! 454: return rc; ! 455: } ! 456: ! 457: /** ! 458: * Open network device ! 459: * ! 460: * @v netdev Network device ! 461: * @ret rc Return status code ! 462: */ ! 463: int netdev_open ( struct net_device *netdev ) { ! 464: int rc; ! 465: ! 466: /* Do nothing if device is already open */ ! 467: if ( netdev->state & NETDEV_OPEN ) ! 468: return 0; ! 469: ! 470: DBGC ( netdev, "NETDEV %s opening\n", netdev->name ); ! 471: ! 472: /* Open the device */ ! 473: if ( ( rc = netdev->op->open ( netdev ) ) != 0 ) ! 474: return rc; ! 475: ! 476: /* Mark as opened */ ! 477: netdev->state |= NETDEV_OPEN; ! 478: ! 479: /* Add to head of open devices list */ ! 480: list_add ( &netdev->open_list, &open_net_devices ); ! 481: ! 482: /* Notify drivers of device state change */ ! 483: netdev_notify ( netdev ); ! 484: ! 485: return 0; ! 486: } ! 487: ! 488: /** ! 489: * Close network device ! 490: * ! 491: * @v netdev Network device ! 492: */ ! 493: void netdev_close ( struct net_device *netdev ) { ! 494: ! 495: /* Do nothing if device is already closed */ ! 496: if ( ! ( netdev->state & NETDEV_OPEN ) ) ! 497: return; ! 498: ! 499: DBGC ( netdev, "NETDEV %s closing\n", netdev->name ); ! 500: ! 501: /* Remove from open devices list */ ! 502: list_del ( &netdev->open_list ); ! 503: ! 504: /* Mark as closed */ ! 505: netdev->state &= ~NETDEV_OPEN; ! 506: ! 507: /* Notify drivers of device state change */ ! 508: netdev_notify ( netdev ); ! 509: ! 510: /* Close the device */ ! 511: netdev->op->close ( netdev ); ! 512: ! 513: /* Flush TX and RX queues */ ! 514: netdev_tx_flush ( netdev ); ! 515: netdev_rx_flush ( netdev ); ! 516: } ! 517: ! 518: /** ! 519: * Unregister network device ! 520: * ! 521: * @v netdev Network device ! 522: * ! 523: * Removes the network device from the list of network devices. ! 524: */ ! 525: void unregister_netdev ( struct net_device *netdev ) { ! 526: struct net_driver *driver; ! 527: ! 528: /* Ensure device is closed */ ! 529: netdev_close ( netdev ); ! 530: ! 531: /* Remove device */ ! 532: for_each_table_entry_reverse ( driver, NET_DRIVERS ) ! 533: driver->remove ( netdev ); ! 534: ! 535: /* Unregister per-netdev configuration settings */ ! 536: unregister_settings ( netdev_settings ( netdev ) ); ! 537: ! 538: /* Remove from device list */ ! 539: list_del ( &netdev->list ); ! 540: netdev_put ( netdev ); ! 541: DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name ); ! 542: } ! 543: ! 544: /** Enable or disable interrupts ! 545: * ! 546: * @v netdev Network device ! 547: * @v enable Interrupts should be enabled ! 548: */ ! 549: void netdev_irq ( struct net_device *netdev, int enable ) { ! 550: ! 551: /* Do nothing if device does not support interrupts */ ! 552: if ( ! netdev_irq_supported ( netdev ) ) ! 553: return; ! 554: ! 555: /* Enable or disable device interrupts */ ! 556: netdev->op->irq ( netdev, enable ); ! 557: ! 558: /* Record interrupt enabled state */ ! 559: netdev->state &= ~NETDEV_IRQ_ENABLED; ! 560: if ( enable ) ! 561: netdev->state |= NETDEV_IRQ_ENABLED; ! 562: } ! 563: ! 564: /** ! 565: * Get network device by name ! 566: * ! 567: * @v name Network device name ! 568: * @ret netdev Network device, or NULL ! 569: */ ! 570: struct net_device * find_netdev ( const char *name ) { ! 571: struct net_device *netdev; ! 572: ! 573: list_for_each_entry ( netdev, &net_devices, list ) { ! 574: if ( strcmp ( netdev->name, name ) == 0 ) ! 575: return netdev; ! 576: } ! 577: ! 578: return NULL; ! 579: } ! 580: ! 581: /** ! 582: * Get network device by PCI bus:dev.fn address ! 583: * ! 584: * @v bus_type Bus type ! 585: * @v location Bus location ! 586: * @ret netdev Network device, or NULL ! 587: */ ! 588: struct net_device * find_netdev_by_location ( unsigned int bus_type, ! 589: unsigned int location ) { ! 590: struct net_device *netdev; ! 591: ! 592: list_for_each_entry ( netdev, &net_devices, list ) { ! 593: if ( ( netdev->dev->desc.bus_type == bus_type ) && ! 594: ( netdev->dev->desc.location == location ) ) ! 595: return netdev; ! 596: } ! 597: ! 598: return NULL; ! 599: } ! 600: ! 601: /** ! 602: * Get most recently opened network device ! 603: * ! 604: * @ret netdev Most recently opened network device, or NULL ! 605: */ ! 606: struct net_device * last_opened_netdev ( void ) { ! 607: struct net_device *netdev; ! 608: ! 609: netdev = list_first_entry ( &open_net_devices, struct net_device, ! 610: open_list ); ! 611: if ( ! netdev ) ! 612: return NULL; ! 613: ! 614: assert ( netdev_is_open ( netdev ) ); ! 615: return netdev; ! 616: } ! 617: ! 618: /** ! 619: * Transmit network-layer packet ! 620: * ! 621: * @v iobuf I/O buffer ! 622: * @v netdev Network device ! 623: * @v net_protocol Network-layer protocol ! 624: * @v ll_dest Destination link-layer address ! 625: * @v ll_source Source link-layer address ! 626: * @ret rc Return status code ! 627: * ! 628: * Prepends link-layer headers to the I/O buffer and transmits the ! 629: * packet via the specified network device. This function takes ! 630: * ownership of the I/O buffer. ! 631: */ ! 632: int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, ! 633: struct net_protocol *net_protocol, const void *ll_dest, ! 634: const void *ll_source ) { ! 635: struct ll_protocol *ll_protocol = netdev->ll_protocol; ! 636: int rc; ! 637: ! 638: /* Force a poll on the netdevice to (potentially) clear any ! 639: * backed-up TX completions. This is needed on some network ! 640: * devices to avoid excessive losses due to small TX ring ! 641: * sizes. ! 642: */ ! 643: netdev_poll ( netdev ); ! 644: ! 645: /* Add link-layer header */ ! 646: if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, ll_source, ! 647: net_protocol->net_proto ) ) != 0 ) { ! 648: free_iob ( iobuf ); ! 649: return rc; ! 650: } ! 651: ! 652: /* Transmit packet */ ! 653: return netdev_tx ( netdev, iobuf ); ! 654: } ! 655: ! 656: /** ! 657: * Process received network-layer packet ! 658: * ! 659: * @v iobuf I/O buffer ! 660: * @v netdev Network device ! 661: * @v net_proto Network-layer protocol, in network-byte order ! 662: * @v ll_dest Destination link-layer address ! 663: * @v ll_source Source link-layer address ! 664: * @ret rc Return status code ! 665: */ ! 666: int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, ! 667: uint16_t net_proto, const void *ll_dest, const void *ll_source ) { ! 668: struct net_protocol *net_protocol; ! 669: ! 670: /* Hand off to network-layer protocol, if any */ ! 671: for_each_table_entry ( net_protocol, NET_PROTOCOLS ) { ! 672: if ( net_protocol->net_proto == net_proto ) ! 673: return net_protocol->rx ( iobuf, netdev, ll_dest, ! 674: ll_source ); ! 675: } ! 676: ! 677: DBGC ( netdev, "NETDEV %s unknown network protocol %04x\n", ! 678: netdev->name, ntohs ( net_proto ) ); ! 679: free_iob ( iobuf ); ! 680: return -ENOTSUP; ! 681: } ! 682: ! 683: /** ! 684: * Poll the network stack ! 685: * ! 686: * This polls all interfaces for received packets, and processes ! 687: * packets from the RX queue. ! 688: */ ! 689: void net_poll ( void ) { ! 690: struct net_device *netdev; ! 691: struct io_buffer *iobuf; ! 692: struct ll_protocol *ll_protocol; ! 693: const void *ll_dest; ! 694: const void *ll_source; ! 695: uint16_t net_proto; ! 696: int rc; ! 697: ! 698: /* Poll and process each network device */ ! 699: list_for_each_entry ( netdev, &net_devices, list ) { ! 700: ! 701: /* Poll for new packets */ ! 702: netdev_poll ( netdev ); ! 703: ! 704: /* Leave received packets on the queue if receive ! 705: * queue processing is currently frozen. This will ! 706: * happen when the raw packets are to be manually ! 707: * dequeued using netdev_rx_dequeue(), rather than ! 708: * processed via the usual networking stack. ! 709: */ ! 710: if ( netdev_rx_frozen ( netdev ) ) ! 711: continue; ! 712: ! 713: /* Process at most one received packet. Give priority ! 714: * to getting packets out of the NIC over processing ! 715: * the received packets, because we advertise a window ! 716: * that assumes that we can receive packets from the ! 717: * NIC faster than they arrive. ! 718: */ ! 719: if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) { ! 720: ! 721: DBGC ( netdev, "NETDEV %s processing %p (%p+%zx)\n", ! 722: netdev->name, iobuf, iobuf->data, ! 723: iob_len ( iobuf ) ); ! 724: ! 725: /* Remove link-layer header */ ! 726: ll_protocol = netdev->ll_protocol; ! 727: if ( ( rc = ll_protocol->pull ( netdev, iobuf, ! 728: &ll_dest, &ll_source, ! 729: &net_proto ) ) != 0 ) { ! 730: free_iob ( iobuf ); ! 731: continue; ! 732: } ! 733: ! 734: /* Hand packet to network layer */ ! 735: if ( ( rc = net_rx ( iob_disown ( iobuf ), netdev, ! 736: net_proto, ll_dest, ! 737: ll_source ) ) != 0 ) { ! 738: /* Record error for diagnosis */ ! 739: netdev_rx_err ( netdev, NULL, rc ); ! 740: } ! 741: } ! 742: } ! 743: } ! 744: ! 745: /** ! 746: * Single-step the network stack ! 747: * ! 748: * @v process Network stack process ! 749: */ ! 750: static void net_step ( struct process *process __unused ) { ! 751: net_poll(); ! 752: } ! 753: ! 754: /** Networking stack process */ ! 755: struct process net_process __permanent_process = { ! 756: .list = LIST_HEAD_INIT ( net_process.list ), ! 757: .step = net_step, ! 758: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.