[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / net / netdevice.c
blob00b4478e9eb2294ac511664df7ca9bd6f70fac06
1 /*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
19 FILE_LICENCE ( GPL2_OR_LATER );
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 <gpxe/if_ether.h>
28 #include <gpxe/iobuf.h>
29 #include <gpxe/tables.h>
30 #include <gpxe/process.h>
31 #include <gpxe/init.h>
32 #include <gpxe/device.h>
33 #include <gpxe/errortab.h>
34 #include <gpxe/netdevice.h>
36 /** @file
38 * Network device management
42 /** List of network devices */
43 struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
45 /** List of open network devices, in reverse order of opening */
46 static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
48 /** Default link status code */
49 #define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS )
50 #define EINFO_EUNKNOWN_LINK_STATUS \
51 __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
53 /** Human-readable message for the default link status */
54 struct errortab netdev_errors[] __errortab = {
55 __einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
58 /**
59 * Mark network device as having link down
61 * @v netdev Network device
63 void netdev_link_down ( struct net_device *netdev ) {
65 /* Avoid clobbering a more detailed link status code, if one
66 * is already set.
68 if ( ( netdev->link_rc == 0 ) ||
69 ( netdev->link_rc == -EUNKNOWN_LINK_STATUS ) ) {
70 netdev->link_rc = -ENOTCONN;
74 /**
75 * Record network device statistic
77 * @v stats Network device statistics
78 * @v rc Status code
80 static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
81 struct net_device_error *error;
82 struct net_device_error *least_common_error;
83 unsigned int i;
85 /* If this is not an error, just update the good counter */
86 if ( rc == 0 ) {
87 stats->good++;
88 return;
91 /* Update the bad counter */
92 stats->bad++;
94 /* Locate the appropriate error record */
95 least_common_error = &stats->errors[0];
96 for ( i = 0 ; i < ( sizeof ( stats->errors ) /
97 sizeof ( stats->errors[0] ) ) ; i++ ) {
98 error = &stats->errors[i];
99 /* Update matching record, if found */
100 if ( error->rc == rc ) {
101 error->count++;
102 return;
104 if ( error->count < least_common_error->count )
105 least_common_error = error;
108 /* Overwrite the least common error record */
109 least_common_error->rc = rc;
110 least_common_error->count = 1;
114 * Transmit raw packet via network device
116 * @v netdev Network device
117 * @v iobuf I/O buffer
118 * @ret rc Return status code
120 * Transmits the packet via the specified network device. This
121 * function takes ownership of the I/O buffer.
123 int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
124 int rc;
126 DBGC ( netdev, "NETDEV %p transmitting %p (%p+%zx)\n",
127 netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
129 list_add_tail ( &iobuf->list, &netdev->tx_queue );
131 if ( ! netdev_is_open ( netdev ) ) {
132 rc = -ENETUNREACH;
133 goto err;
136 if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 )
137 goto err;
139 return 0;
141 err:
142 netdev_tx_complete_err ( netdev, iobuf, rc );
143 return rc;
147 * Complete network transmission
149 * @v netdev Network device
150 * @v iobuf I/O buffer
151 * @v rc Packet status code
153 * The packet must currently be in the network device's TX queue.
155 void netdev_tx_complete_err ( struct net_device *netdev,
156 struct io_buffer *iobuf, int rc ) {
158 /* Update statistics counter */
159 netdev_record_stat ( &netdev->tx_stats, rc );
160 if ( rc == 0 ) {
161 DBGC ( netdev, "NETDEV %p transmission %p complete\n",
162 netdev, iobuf );
163 } else {
164 DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
165 netdev, iobuf, strerror ( rc ) );
168 /* Catch data corruption as early as possible */
169 assert ( iobuf->list.next != NULL );
170 assert ( iobuf->list.prev != NULL );
172 /* Dequeue and free I/O buffer */
173 list_del ( &iobuf->list );
174 free_iob ( iobuf );
178 * Complete network transmission
180 * @v netdev Network device
181 * @v rc Packet status code
183 * Completes the oldest outstanding packet in the TX queue.
185 void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) {
186 struct io_buffer *iobuf;
188 list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
189 netdev_tx_complete_err ( netdev, iobuf, rc );
190 return;
195 * Flush device's transmit queue
197 * @v netdev Network device
199 static void netdev_tx_flush ( struct net_device *netdev ) {
201 /* Discard any packets in the TX queue */
202 while ( ! list_empty ( &netdev->tx_queue ) ) {
203 netdev_tx_complete_next_err ( netdev, -ECANCELED );
208 * Add packet to receive queue
210 * @v netdev Network device
211 * @v iobuf I/O buffer, or NULL
213 * The packet is added to the network device's RX queue. This
214 * function takes ownership of the I/O buffer.
216 void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
218 DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
219 netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
221 /* Enqueue packet */
222 list_add_tail ( &iobuf->list, &netdev->rx_queue );
224 /* Update statistics counter */
225 netdev_record_stat ( &netdev->rx_stats, 0 );
229 * Discard received packet
231 * @v netdev Network device
232 * @v iobuf I/O buffer, or NULL
233 * @v rc Packet status code
235 * The packet is discarded and an RX error is recorded. This function
236 * takes ownership of the I/O buffer. @c iobuf may be NULL if, for
237 * example, the net device wishes to report an error due to being
238 * unable to allocate an I/O buffer.
240 void netdev_rx_err ( struct net_device *netdev,
241 struct io_buffer *iobuf, int rc ) {
243 DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n",
244 netdev, iobuf, strerror ( rc ) );
246 /* Discard packet */
247 free_iob ( iobuf );
249 /* Update statistics counter */
250 netdev_record_stat ( &netdev->rx_stats, rc );
254 * Poll for completed and received packets on network device
256 * @v netdev Network device
258 * Polls the network device for completed transmissions and received
259 * packets. Any received packets will be added to the RX packet queue
260 * via netdev_rx().
262 void netdev_poll ( struct net_device *netdev ) {
264 if ( netdev_is_open ( netdev ) )
265 netdev->op->poll ( netdev );
269 * Remove packet from device's receive queue
271 * @v netdev Network device
272 * @ret iobuf I/O buffer, or NULL
274 * Removes the first packet from the device's RX queue and returns it.
275 * Ownership of the packet is transferred to the caller.
277 struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) {
278 struct io_buffer *iobuf;
280 list_for_each_entry ( iobuf, &netdev->rx_queue, list ) {
281 list_del ( &iobuf->list );
282 return iobuf;
284 return NULL;
288 * Flush device's receive queue
290 * @v netdev Network device
292 static void netdev_rx_flush ( struct net_device *netdev ) {
293 struct io_buffer *iobuf;
295 /* Discard any packets in the RX queue */
296 while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
297 netdev_rx_err ( netdev, iobuf, -ECANCELED );
302 * Free network device
304 * @v refcnt Network device reference counter
306 static void free_netdev ( struct refcnt *refcnt ) {
307 struct net_device *netdev =
308 container_of ( refcnt, struct net_device, refcnt );
310 netdev_tx_flush ( netdev );
311 netdev_rx_flush ( netdev );
312 clear_settings ( netdev_settings ( netdev ) );
313 free ( netdev );
317 * Allocate network device
319 * @v priv_size Size of private data area (net_device::priv)
320 * @ret netdev Network device, or NULL
322 * Allocates space for a network device and its private data area.
324 struct net_device * alloc_netdev ( size_t priv_size ) {
325 struct net_device *netdev;
326 size_t total_len;
328 total_len = ( sizeof ( *netdev ) + priv_size );
329 netdev = zalloc ( total_len );
330 if ( netdev ) {
331 ref_init ( &netdev->refcnt, free_netdev );
332 netdev->link_rc = -EUNKNOWN_LINK_STATUS;
333 INIT_LIST_HEAD ( &netdev->tx_queue );
334 INIT_LIST_HEAD ( &netdev->rx_queue );
335 netdev_settings_init ( netdev );
336 netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
338 return netdev;
342 * Register network device
344 * @v netdev Network device
345 * @ret rc Return status code
347 * Gives the network device a name and adds it to the list of network
348 * devices.
350 int register_netdev ( struct net_device *netdev ) {
351 static unsigned int ifindex = 0;
352 int rc;
354 /* Create device name */
355 snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
356 ifindex++ );
358 /* Set initial link-layer address */
359 netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
361 /* Register per-netdev configuration settings */
362 if ( ( rc = register_settings ( netdev_settings ( netdev ),
363 NULL ) ) != 0 ) {
364 DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
365 netdev, strerror ( rc ) );
366 return rc;
369 /* Add to device list */
370 netdev_get ( netdev );
371 list_add_tail ( &netdev->list, &net_devices );
372 DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n",
373 netdev, netdev->name, netdev->dev->name,
374 netdev_addr ( netdev ) );
376 return 0;
380 * Open network device
382 * @v netdev Network device
383 * @ret rc Return status code
385 int netdev_open ( struct net_device *netdev ) {
386 int rc;
388 /* Do nothing if device is already open */
389 if ( netdev->state & NETDEV_OPEN )
390 return 0;
392 DBGC ( netdev, "NETDEV %p opening\n", netdev );
394 /* Open the device */
395 if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
396 return rc;
398 /* Mark as opened */
399 netdev->state |= NETDEV_OPEN;
401 /* Add to head of open devices list */
402 list_add ( &netdev->open_list, &open_net_devices );
404 return 0;
408 * Close network device
410 * @v netdev Network device
412 void netdev_close ( struct net_device *netdev ) {
414 /* Do nothing if device is already closed */
415 if ( ! ( netdev->state & NETDEV_OPEN ) )
416 return;
418 DBGC ( netdev, "NETDEV %p closing\n", netdev );
420 /* Close the device */
421 netdev->op->close ( netdev );
423 /* Flush TX and RX queues */
424 netdev_tx_flush ( netdev );
425 netdev_rx_flush ( netdev );
427 /* Mark as closed */
428 netdev->state &= ~NETDEV_OPEN;
430 /* Remove from open devices list */
431 list_del ( &netdev->open_list );
435 * Unregister network device
437 * @v netdev Network device
439 * Removes the network device from the list of network devices.
441 void unregister_netdev ( struct net_device *netdev ) {
443 /* Ensure device is closed */
444 netdev_close ( netdev );
446 /* Unregister per-netdev configuration settings */
447 unregister_settings ( netdev_settings ( netdev ) );
449 /* Remove from device list */
450 list_del ( &netdev->list );
451 netdev_put ( netdev );
452 DBGC ( netdev, "NETDEV %p unregistered\n", netdev );
455 /** Enable or disable interrupts
457 * @v netdev Network device
458 * @v enable Interrupts should be enabled
460 void netdev_irq ( struct net_device *netdev, int enable ) {
462 /* Enable or disable device interrupts */
463 netdev->op->irq ( netdev, enable );
465 /* Record interrupt enabled state */
466 netdev->state &= ~NETDEV_IRQ_ENABLED;
467 if ( enable )
468 netdev->state |= NETDEV_IRQ_ENABLED;
472 * Get network device by name
474 * @v name Network device name
475 * @ret netdev Network device, or NULL
477 struct net_device * find_netdev ( const char *name ) {
478 struct net_device *netdev;
480 list_for_each_entry ( netdev, &net_devices, list ) {
481 if ( strcmp ( netdev->name, name ) == 0 )
482 return netdev;
485 return NULL;
489 * Get network device by PCI bus:dev.fn address
491 * @v bus_type Bus type
492 * @v location Bus location
493 * @ret netdev Network device, or NULL
495 struct net_device * find_netdev_by_location ( unsigned int bus_type,
496 unsigned int location ) {
497 struct net_device *netdev;
499 list_for_each_entry ( netdev, &net_devices, list ) {
500 if ( ( netdev->dev->desc.bus_type == bus_type ) &&
501 ( netdev->dev->desc.location == location ) )
502 return netdev;
505 return NULL;
509 * Get most recently opened network device
511 * @ret netdev Most recently opened network device, or NULL
513 struct net_device * last_opened_netdev ( void ) {
514 struct net_device *netdev;
516 list_for_each_entry ( netdev, &open_net_devices, open_list ) {
517 assert ( netdev_is_open ( netdev ) );
518 return netdev;
521 return NULL;
525 * Transmit network-layer packet
527 * @v iobuf I/O buffer
528 * @v netdev Network device
529 * @v net_protocol Network-layer protocol
530 * @v ll_dest Destination link-layer address
531 * @ret rc Return status code
533 * Prepends link-layer headers to the I/O buffer and transmits the
534 * packet via the specified network device. This function takes
535 * ownership of the I/O buffer.
537 int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
538 struct net_protocol *net_protocol, const void *ll_dest ) {
539 struct ll_protocol *ll_protocol = netdev->ll_protocol;
540 int rc;
542 /* Force a poll on the netdevice to (potentially) clear any
543 * backed-up TX completions. This is needed on some network
544 * devices to avoid excessive losses due to small TX ring
545 * sizes.
547 netdev_poll ( netdev );
549 /* Add link-layer header */
550 if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, netdev->ll_addr,
551 net_protocol->net_proto ) ) != 0 ) {
552 free_iob ( iobuf );
553 return rc;
556 /* Transmit packet */
557 return netdev_tx ( netdev, iobuf );
561 * Process received network-layer packet
563 * @v iobuf I/O buffer
564 * @v netdev Network device
565 * @v net_proto Network-layer protocol, in network-byte order
566 * @v ll_source Source link-layer address
567 * @ret rc Return status code
569 int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
570 uint16_t net_proto, const void *ll_source ) {
571 struct net_protocol *net_protocol;
573 /* Hand off to network-layer protocol, if any */
574 for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
575 if ( net_protocol->net_proto == net_proto )
576 return net_protocol->rx ( iobuf, netdev, ll_source );
579 DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n",
580 netdev, ntohs ( net_proto ) );
581 free_iob ( iobuf );
582 return 0;
586 * Single-step the network stack
588 * @v process Network stack process
590 * This polls all interfaces for received packets, and processes
591 * packets from the RX queue.
593 static void net_step ( struct process *process __unused ) {
594 struct net_device *netdev;
595 struct io_buffer *iobuf;
596 struct ll_protocol *ll_protocol;
597 const void *ll_dest;
598 const void *ll_source;
599 uint16_t net_proto;
600 int rc;
602 /* Poll and process each network device */
603 list_for_each_entry ( netdev, &net_devices, list ) {
605 /* Poll for new packets */
606 netdev_poll ( netdev );
608 /* Process at most one received packet. Give priority
609 * to getting packets out of the NIC over processing
610 * the received packets, because we advertise a window
611 * that assumes that we can receive packets from the
612 * NIC faster than they arrive.
614 if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
616 DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n",
617 netdev, iobuf, iobuf->data,
618 iob_len ( iobuf ) );
620 /* Remove link-layer header */
621 ll_protocol = netdev->ll_protocol;
622 if ( ( rc = ll_protocol->pull ( netdev, iobuf,
623 &ll_dest, &ll_source,
624 &net_proto ) ) != 0 ) {
625 free_iob ( iobuf );
626 continue;
629 net_rx ( iobuf, netdev, net_proto, ll_source );
634 /** Networking stack process */
635 struct process net_process __permanent_process = {
636 .list = LIST_HEAD_INIT ( net_process.list ),
637 .step = net_step,