From 24fc6aa5b03ac1b8506a8897996324e1c78b7b5a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 18 Nov 2010 17:41:02 +0000 Subject: [PATCH 01/85] [netdevice] Use net device name in debugging messages Signed-off-by: Michael Brown --- src/net/eth_slow.c | 20 ++++++++--------- src/net/netdevice.c | 53 +++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/net/eth_slow.c b/src/net/eth_slow.c index e5c7ec9d..45980182 100644 --- a/src/net/eth_slow.c +++ b/src/net/eth_slow.c @@ -111,23 +111,23 @@ static void eth_slow_lacp_dump ( struct io_buffer *iobuf, struct eth_slow_lacp *lacp = ð_slow->lacp; DBGC ( netdev, - "SLOW %p %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n", - netdev, label, ntohs ( lacp->actor.system_priority ), + "SLOW %s %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n", + netdev->name, label, ntohs ( lacp->actor.system_priority ), eth_ntoa ( lacp->actor.system ), ntohs ( lacp->actor.key ), ntohs ( lacp->actor.port_priority ), ntohs ( lacp->actor.port ), eth_slow_lacp_state_name ( lacp->actor.state ) ); DBGC ( netdev, - "SLOW %p %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n", - netdev, label, ntohs ( lacp->partner.system_priority ), + "SLOW %s %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n", + netdev->name, label, ntohs ( lacp->partner.system_priority ), eth_ntoa ( lacp->partner.system ), ntohs ( lacp->partner.key ), ntohs ( lacp->partner.port_priority ), ntohs ( lacp->partner.port ), eth_slow_lacp_state_name ( lacp->partner.state ) ); - DBGC ( netdev, "SLOW %p %s LACP collector %04x (%d us)\n", - netdev, label, ntohs ( lacp->collector.max_delay ), + DBGC ( netdev, "SLOW %s %s LACP collector %04x (%d us)\n", + netdev->name, label, ntohs ( lacp->collector.max_delay ), ( ntohs ( lacp->collector.max_delay ) * 10 ) ); DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) ); } @@ -191,8 +191,8 @@ static void eth_slow_marker_dump ( struct io_buffer *iobuf, union eth_slow_packet *eth_slow = iobuf->data; struct eth_slow_marker *marker = ð_slow->marker; - DBGC ( netdev, "SLOW %p %s marker %s port %04x system %s xact %08x\n", - netdev, label, + DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n", + netdev->name, label, eth_slow_marker_tlv_name ( marker->marker.tlv.type ), ntohs ( marker->marker.port ), eth_ntoa ( marker->marker.system ), @@ -255,8 +255,8 @@ static int eth_slow_rx ( struct io_buffer *iobuf, case ETH_SLOW_SUBTYPE_MARKER: return eth_slow_marker_rx ( iobuf, netdev ); default: - DBGC ( netdev, "SLOW %p RX unknown subtype %02x\n", - netdev, eth_slow->header.subtype ); + DBGC ( netdev, "SLOW %s RX unknown subtype %02x\n", + netdev->name, eth_slow->header.subtype ); free_iob ( iobuf ); return -EINVAL; } diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 9da4ce47..c6c377b5 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -79,10 +79,10 @@ void netdev_link_err ( struct net_device *netdev, int rc ) { /* Record link state */ netdev->link_rc = rc; if ( netdev->link_rc == 0 ) { - DBGC ( netdev, "NETDEV %p link is up\n", netdev ); + DBGC ( netdev, "NETDEV %s link is up\n", netdev->name ); } else { - DBGC ( netdev, "NETDEV %p link is down: %s\n", - netdev, strerror ( netdev->link_rc ) ); + DBGC ( netdev, "NETDEV %s link is down: %s\n", + netdev->name, strerror ( netdev->link_rc ) ); } /* Notify drivers of link state change */ @@ -157,8 +157,8 @@ static void netdev_record_stat ( struct net_device_stats *stats, int rc ) { int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { int rc; - DBGC ( netdev, "NETDEV %p transmitting %p (%p+%zx)\n", - netdev, iobuf, iobuf->data, iob_len ( iobuf ) ); + DBGC ( netdev, "NETDEV %s transmitting %p (%p+%zx)\n", + netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) ); /* Enqueue packet */ list_add_tail ( &iobuf->list, &netdev->tx_queue ); @@ -202,11 +202,11 @@ void netdev_tx_complete_err ( struct net_device *netdev, /* Update statistics counter */ netdev_record_stat ( &netdev->tx_stats, rc ); if ( rc == 0 ) { - DBGC ( netdev, "NETDEV %p transmission %p complete\n", - netdev, iobuf ); + DBGC ( netdev, "NETDEV %s transmission %p complete\n", + netdev->name, iobuf ); } else { - DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n", - netdev, iobuf, strerror ( rc ) ); + DBGC ( netdev, "NETDEV %s transmission %p failed: %s\n", + netdev->name, iobuf, strerror ( rc ) ); } /* Catch data corruption as early as possible */ @@ -259,8 +259,8 @@ static void netdev_tx_flush ( struct net_device *netdev ) { */ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { - DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n", - netdev, iobuf, iobuf->data, iob_len ( iobuf ) ); + DBGC ( netdev, "NETDEV %s received %p (%p+%zx)\n", + netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) ); /* Discard packet (for test purposes) if applicable */ if ( ( NETDEV_DISCARD_RATE > 0 ) && @@ -291,8 +291,8 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { void netdev_rx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { - DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n", - netdev, iobuf, strerror ( rc ) ); + DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n", + netdev->name, iobuf, strerror ( rc ) ); /* Discard packet */ free_iob ( iobuf ); @@ -414,23 +414,24 @@ int register_netdev ( struct net_device *netdev ) { /* Add to device list */ netdev_get ( netdev ); list_add_tail ( &netdev->list, &net_devices ); - DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n", - netdev, netdev->name, netdev->dev->name, + DBGC ( netdev, "NETDEV %s registered (phys %s hwaddr %s)\n", + netdev->name, netdev->dev->name, netdev_addr ( netdev ) ); /* Register per-netdev configuration settings */ if ( ( rc = register_settings ( netdev_settings ( netdev ), NULL ) ) != 0 ) { - DBGC ( netdev, "NETDEV %p could not register settings: %s\n", - netdev, strerror ( rc ) ); + DBGC ( netdev, "NETDEV %s could not register settings: %s\n", + netdev->name, strerror ( rc ) ); goto err_register_settings; } /* Probe device */ for_each_table_entry ( driver, NET_DRIVERS ) { if ( ( rc = driver->probe ( netdev ) ) != 0 ) { - DBGC ( netdev, "NETDEV %p could not add %s device: " - "%s\n", netdev, driver->name, strerror ( rc ) ); + DBGC ( netdev, "NETDEV %s could not add %s device: " + "%s\n", netdev->name, driver->name, + strerror ( rc ) ); goto err_probe; } } @@ -458,7 +459,7 @@ int netdev_open ( struct net_device *netdev ) { if ( netdev->state & NETDEV_OPEN ) return 0; - DBGC ( netdev, "NETDEV %p opening\n", netdev ); + DBGC ( netdev, "NETDEV %s opening\n", netdev->name ); /* Open the device */ if ( ( rc = netdev->op->open ( netdev ) ) != 0 ) @@ -487,7 +488,7 @@ void netdev_close ( struct net_device *netdev ) { if ( ! ( netdev->state & NETDEV_OPEN ) ) return; - DBGC ( netdev, "NETDEV %p closing\n", netdev ); + DBGC ( netdev, "NETDEV %s closing\n", netdev->name ); /* Remove from open devices list */ list_del ( &netdev->open_list ); @@ -529,7 +530,7 @@ void unregister_netdev ( struct net_device *netdev ) { /* Remove from device list */ list_del ( &netdev->list ); netdev_put ( netdev ); - DBGC ( netdev, "NETDEV %p unregistered\n", netdev ); + DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name ); } /** Enable or disable interrupts @@ -661,8 +662,8 @@ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, ll_source ); } - DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n", - netdev, ntohs ( net_proto ) ); + DBGC ( netdev, "NETDEV %s unknown network protocol %04x\n", + netdev->name, ntohs ( net_proto ) ); free_iob ( iobuf ); return -ENOTSUP; } @@ -698,8 +699,8 @@ static void net_step ( struct process *process __unused ) { */ if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) { - DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n", - netdev, iobuf, iobuf->data, + DBGC ( netdev, "NETDEV %s processing %p (%p+%zx)\n", + netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) ); /* Remove link-layer header */ From 3d9096f7192bd153f4b1bec32dc8902fc3704594 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 18 Nov 2010 17:41:44 +0000 Subject: [PATCH 02/85] [lacp] Fix dumping of raw LACP packets Signed-off-by: Michael Brown --- src/net/eth_slow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/eth_slow.c b/src/net/eth_slow.c index 45980182..9e68939c 100644 --- a/src/net/eth_slow.c +++ b/src/net/eth_slow.c @@ -129,7 +129,7 @@ static void eth_slow_lacp_dump ( struct io_buffer *iobuf, DBGC ( netdev, "SLOW %s %s LACP collector %04x (%d us)\n", netdev->name, label, ntohs ( lacp->collector.max_delay ), ( ntohs ( lacp->collector.max_delay ) * 10 ) ); - DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) ); + DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); } /** @@ -197,7 +197,7 @@ static void eth_slow_marker_dump ( struct io_buffer *iobuf, ntohs ( marker->marker.port ), eth_ntoa ( marker->marker.system ), ntohl ( marker->marker.xact ) ); - DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) ); + DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); } /** From 1782fc7011a725386075fff00989f19c5f4b7530 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 18 Nov 2010 23:30:50 +0000 Subject: [PATCH 03/85] [lotest] Move lotest.h to correct directory Signed-off-by: Michael Brown --- src/{ => include}/usr/lotest.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => include}/usr/lotest.h (100%) diff --git a/src/usr/lotest.h b/src/include/usr/lotest.h similarity index 100% rename from src/usr/lotest.h rename to src/include/usr/lotest.h From 308615cd97ec9a17cdbd184626038ef5e5e28443 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 15:32:05 +0000 Subject: [PATCH 04/85] [efi] Always allow MAX_LL_HEADER_LEN for the link-layer header Signed-off-by: Michael Brown --- src/interface/efi/efi_snp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index 01b6b506..43620f57 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -530,6 +530,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, container_of ( snp, struct efi_snp_device, snp ); struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; struct io_buffer *iobuf; + size_t ll_headroom; int rc; EFI_STATUS efirc; @@ -582,13 +583,15 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, } /* Allocate buffer */ - iobuf = alloc_iob ( len ); + ll_headroom = ( MAX_LL_HEADER_LEN - ll_header_len ); + iobuf = alloc_iob ( ll_headroom + len ); if ( ! iobuf ) { DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte " "buffer\n", snpdev, ( ( unsigned long ) len ) ); efirc = EFI_DEVICE_ERROR; goto err_alloc_iob; } + iob_reserve ( iobuf, ll_headroom ); memcpy ( iob_put ( iobuf, len ), data, len ); /* Create link-layer header, if specified */ From fb78d086f1376dcc88abb010d2fa8aa043c8fedd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 15:37:08 +0000 Subject: [PATCH 05/85] [pxe] Always allow MAX_LL_HEADER_LEN for the link-layer header Signed-off-by: Michael Brown --- src/arch/i386/interface/pxe/pxe_undi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/arch/i386/interface/pxe/pxe_undi.c b/src/arch/i386/interface/pxe/pxe_undi.c index 3ebee94e..27f3c801 100644 --- a/src/arch/i386/interface/pxe/pxe_undi.c +++ b/src/arch/i386/interface/pxe/pxe_undi.c @@ -228,7 +228,6 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; char destaddr[MAX_LL_ADDR_LEN]; const void *ll_dest; - size_t ll_hlen = ll_protocol->ll_header_len; size_t len; unsigned int i; int rc; @@ -248,7 +247,6 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT case P_RARP: net_protocol = &rarp_protocol; break; case P_UNKNOWN: net_protocol = NULL; - ll_hlen = 0; break; default: DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol ); @@ -271,13 +269,13 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT } /* Allocate and fill I/O buffer */ - iobuf = alloc_iob ( ll_hlen + len ); + iobuf = alloc_iob ( MAX_LL_HEADER_LEN + len ); if ( ! iobuf ) { DBG2 ( " could not allocate iobuf\n" ); undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES; return PXENV_EXIT_FAILURE; } - iob_reserve ( iobuf, ll_hlen ); + iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment, tbd.Xmit.offset, tbd.ImmedLength ); for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { From 0d7839678b9353e8b8c37f2c3311fbf52df9e149 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 15:45:01 +0000 Subject: [PATCH 06/85] [netdevice] Add MAX_NET_HEADER_LEN and MAX_LL_NET_HEADER_LEN Signed-off-by: Michael Brown --- src/include/ipxe/netdevice.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index 8cec33ee..4649377a 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -45,6 +45,16 @@ struct device; /** Maximum length of a network-layer address */ #define MAX_NET_ADDR_LEN 4 +/** Maximum length of a network-layer header + * + * The longest currently-supported network-layer header is for IPv6 at + * 40 bytes. + */ +#define MAX_NET_HEADER_LEN 40 + +/** Maximum combined length of a link-layer and network-layer header */ +#define MAX_LL_NET_HEADER_LEN ( MAX_LL_HEADER_LEN + MAX_NET_HEADER_LEN ) + /** * A network-layer protocol * From 5de4fba4f99e3dbb6da1d1d71aaf2a9d3f8b899f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 15:45:41 +0000 Subject: [PATCH 07/85] [udp] Use MAX_LL_NET_HEADER_LEN instead of defining our own UDP_MAX_HLEN Signed-off-by: Michael Brown --- src/include/ipxe/udp.h | 1 - src/net/udp.c | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/include/ipxe/udp.h b/src/include/ipxe/udp.h index c18a2972..ed049476 100644 --- a/src/include/ipxe/udp.h +++ b/src/include/ipxe/udp.h @@ -23,7 +23,6 @@ struct sockaddr; * UDP constants */ -#define UDP_MAX_HLEN 72 #define UDP_MAX_TXIOB ETH_MAX_MTU #define UDP_MIN_TXIOB ETH_ZLEN diff --git a/src/net/udp.c b/src/net/udp.c index 9bd80f3a..5f452535 100644 --- a/src/net/udp.c +++ b/src/net/udp.c @@ -9,6 +9,7 @@ #include #include #include +#include #include /** @file @@ -197,7 +198,8 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf, int rc; /* Check we can accommodate the header */ - if ( ( rc = iob_ensure_headroom ( iobuf, UDP_MAX_HLEN ) ) != 0 ) { + if ( ( rc = iob_ensure_headroom ( iobuf, + MAX_LL_NET_HEADER_LEN ) ) != 0 ) { free_iob ( iobuf ); return rc; } @@ -361,13 +363,13 @@ static struct io_buffer * udp_xfer_alloc_iob ( struct udp_connection *udp, size_t len ) { struct io_buffer *iobuf; - iobuf = alloc_iob ( UDP_MAX_HLEN + len ); + iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len ); if ( ! iobuf ) { DBGC ( udp, "UDP %p cannot allocate buffer of length %zd\n", udp, len ); return NULL; } - iob_reserve ( iobuf, UDP_MAX_HLEN ); + iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); return iobuf; } From 878a1f4e2f2bc640621b1b35601ceeb565ad3334 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 15:48:05 +0000 Subject: [PATCH 08/85] [udp] Remove obsolete constants Signed-off-by: Michael Brown --- src/include/ipxe/udp.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/include/ipxe/udp.h b/src/include/ipxe/udp.h index ed049476..5717ef21 100644 --- a/src/include/ipxe/udp.h +++ b/src/include/ipxe/udp.h @@ -23,9 +23,6 @@ struct sockaddr; * UDP constants */ -#define UDP_MAX_TXIOB ETH_MAX_MTU -#define UDP_MIN_TXIOB ETH_ZLEN - /** * A UDP header */ From d012f8701887526498b3dc9917b467c6319c7073 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 15:50:02 +0000 Subject: [PATCH 09/85] [tcp] Use MAX_LL_NET_HEADER_LEN instead of defining our own MAX_HDR_LEN Signed-off-by: Michael Brown --- src/include/ipxe/tcp.h | 1 - src/net/tcp.c | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/ipxe/tcp.h b/src/include/ipxe/tcp.h index e6461464..68bb899a 100644 --- a/src/include/ipxe/tcp.h +++ b/src/include/ipxe/tcp.h @@ -258,7 +258,6 @@ struct tcp_options { #define TCP_MIN_PORT 1 /* Some IOB constants */ -#define MAX_HDR_LEN 100 #define MAX_IOB_LEN 1500 #define MIN_IOB_LEN MAX_HDR_LEN + 100 /* To account for padding by LL */ diff --git a/src/net/tcp.c b/src/net/tcp.c index c3104771..3e1aeedc 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -483,14 +484,14 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { start_timer ( &tcp->timer ); /* Allocate I/O buffer */ - iobuf = alloc_iob ( len + MAX_HDR_LEN ); + iobuf = alloc_iob ( len + MAX_LL_NET_HEADER_LEN ); if ( ! iobuf ) { DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x " "%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ), tcp->rcv_ack ); return -ENOMEM; } - iob_reserve ( iobuf, MAX_HDR_LEN ); + iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); /* Fill data payload from transmit queue */ tcp_process_tx_queue ( tcp, len, iobuf, 0 ); @@ -627,14 +628,14 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp, int rc; /* Allocate space for dataless TX buffer */ - iobuf = alloc_iob ( MAX_HDR_LEN ); + iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN ); if ( ! iobuf ) { DBGC ( tcp, "TCP %p could not allocate iobuf for RST " "%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) ); return -ENOMEM; } - iob_reserve ( iobuf, MAX_HDR_LEN ); + iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); /* Construct RST response */ tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) ); From 7e33adcb90c77f996425ff98de12b1b8af110b7f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 15:50:30 +0000 Subject: [PATCH 10/85] [tcp] Remove obsolete constants Signed-off-by: Michael Brown --- src/include/ipxe/tcp.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/include/ipxe/tcp.h b/src/include/ipxe/tcp.h index 68bb899a..197712b1 100644 --- a/src/include/ipxe/tcp.h +++ b/src/include/ipxe/tcp.h @@ -257,10 +257,6 @@ struct tcp_options { /** Smallest port number on which a TCP connection can listen */ #define TCP_MIN_PORT 1 -/* Some IOB constants */ -#define MAX_IOB_LEN 1500 -#define MIN_IOB_LEN MAX_HDR_LEN + 100 /* To account for padding by LL */ - /** * Maxmimum advertised TCP window size * From 006d9f1f60594d6ffd147bea1f08bc753051a50d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 18:48:00 +0000 Subject: [PATCH 11/85] [undi] Support underlying UNDI devices that don't support interrupts Some network cards do not generate interrupts when operated via the UNDI API. Allow for this by waiting for the ISR to be triggered only if the PXE stack advertises that it supports interrupts. When the PXE stack does not advertise interrupt support, we skip the call to PXENV_UNDI_ISR_IN_START and just poll the device using PXENV_UNDI_ISR_IN_PROCESS. This matches the observed behaviour of at least one other PXE NBP (emBoot's winBoot/i), so there is a reasonable chance of this working. Originally-implemented-by: Muralidhar Appalla Signed-off-by: Michael Brown --- src/arch/i386/drivers/net/undinet.c | 48 +++++++++++++++++++---------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index e6c08464..7571574d 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -43,6 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** An UNDI NIC */ struct undi_nic { + /** Device supports IRQs */ + int irq_supported; /** Assigned IRQ number */ unsigned int irq; /** Currently processing ISR */ @@ -251,8 +253,10 @@ static void undinet_poll ( struct net_device *netdev ) { int rc; if ( ! undinic->isr_processing ) { - /* Do nothing unless ISR has been triggered */ - if ( ! undinet_isr_triggered() ) { + /* If interrupts are supported, then do nothing unless + * the ISR has been triggered. + */ + if ( undinic->irq_supported && ( ! undinet_isr_triggered() ) ){ /* Allow interrupt to occur */ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" "nop\n\t" @@ -357,10 +361,12 @@ static int undinet_open ( struct net_device *netdev ) { struct s_PXENV_UNDI_OPEN undi_open; int rc; - /* Hook interrupt service routine and enable interrupt */ - undinet_hook_isr ( undinic->irq ); - enable_irq ( undinic->irq ); - send_eoi ( undinic->irq ); + /* Hook interrupt service routine and enable interrupt if supported */ + if ( undinic->irq_supported ) { + undinet_hook_isr ( undinic->irq ); + enable_irq ( undinic->irq ); + send_eoi ( undinic->irq ); + } /* Set station address. Required for some PXE stacks; will * spuriously fail on others. Ignore failures. We only ever @@ -425,9 +431,11 @@ static void undinet_close ( struct net_device *netdev ) { pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE, &undi_close, sizeof ( undi_close ) ); - /* Disable interrupt and unhook ISR */ - disable_irq ( undinic->irq ); - undinet_unhook_isr ( undinic->irq ); + /* Disable interrupt and unhook ISR if supported */ + if ( undinic->irq_supported ) { + disable_irq ( undinic->irq ); + undinet_unhook_isr ( undinic->irq ); + } DBGC ( undinic, "UNDINIC %p closed\n", undinic ); } @@ -524,13 +532,8 @@ int undinet_probe ( struct undi_device *undi ) { goto err_undi_get_information; memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN ); undinic->irq = undi_info.IntNumber; - if ( undinic->irq > IRQ_MAX ) { - DBGC ( undinic, "UNDINIC %p invalid IRQ %d\n", - undinic, undinic->irq ); - goto err_bad_irq; - } - DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n", - undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq ); + DBGC ( undinic, "UNDINIC %p has MAC address %s\n", + undinic, eth_ntoa ( netdev->hw_addr ) ); /* Get interface information */ memset ( &undi_iface, 0, sizeof ( undi_iface ) ); @@ -541,6 +544,17 @@ int undinet_probe ( struct undi_device *undi ) { DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n", undinic, undi_iface.IfaceType, undi_iface.LinkSpeed, undi_iface.ServiceFlags ); + if ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) { + if ( undinic->irq > IRQ_MAX ) { + DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n", + undinic, undinic->irq ); + rc = -EINVAL; + goto err_bad_irq; + } + undinic->irq_supported = 1; + DBGC ( undinic, "UNDINIC %p uses IRQ %d\n", + undinic, undinic->irq ); + } if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot", sizeof ( undi_iface.IfaceType ) ) == 0 ) { DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n", @@ -559,8 +573,8 @@ int undinet_probe ( struct undi_device *undi ) { return 0; err_register: - err_undi_get_iface_info: err_bad_irq: + err_undi_get_iface_info: err_undi_get_information: err_undi_initialize: /* Shut down UNDI stack */ From 4576c2da587eeb884fbf848021d06d1a7d280e3f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 20 Nov 2010 04:56:25 +0000 Subject: [PATCH 12/85] [netdevice] Allow per-device receive queue processing to be frozen Several use cases (e.g. the UNDI API and the EFI SNP API) require access to the raw network device receive queue, and so currently use manual calls to netdev_poll() on a specific network device in order to prevent received packets from being processed by the network stack. As an alternative, provide a flag that allows receive queue processing to be frozen on a per-device basis. When receive queue processing is frozen, packets will be enqueued as normal, but will not be automatically dequeued and passed up the network stack. Signed-off-by: Michael Brown --- src/include/ipxe/netdevice.h | 39 ++++++++++++++++++++++++++++++++++-- src/net/netdevice.c | 24 ++++++++++++++++++---- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index 4649377a..26e2ab89 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -343,6 +343,9 @@ struct net_device { /** Network device interrupts are enabled */ #define NETDEV_IRQ_ENABLED 0x0002 +/** Network device receive queue processing is frozen */ +#define NETDEV_RX_FROZEN 0x0004 + /** Link-layer protocol table */ #define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" ) @@ -505,7 +508,7 @@ netdev_link_ok ( struct net_device *netdev ) { * Check whether or not network device is open * * @v netdev Network device - * @v is_open Network device is open + * @ret is_open Network device is open */ static inline __attribute__ (( always_inline )) int netdev_is_open ( struct net_device *netdev ) { @@ -516,13 +519,24 @@ netdev_is_open ( struct net_device *netdev ) { * Check whether or not network device interrupts are currently enabled * * @v netdev Network device - * @v irq_enabled Network device interrupts are enabled + * @ret irq_enabled Network device interrupts are enabled */ static inline __attribute__ (( always_inline )) int netdev_irq_enabled ( struct net_device *netdev ) { return ( netdev->state & NETDEV_IRQ_ENABLED ); } +/** + * Check whether or not network device receive queue processing is frozen + * + * @v netdev Network device + * @ret rx_frozen Network device receive queue processing is frozen + */ +static inline __attribute__ (( always_inline )) int +netdev_rx_frozen ( struct net_device *netdev ) { + return ( netdev->state & NETDEV_RX_FROZEN ); +} + extern void netdev_link_err ( struct net_device *netdev, int rc ); extern void netdev_link_down ( struct net_device *netdev ); extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ); @@ -550,6 +564,7 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, uint16_t net_proto, const void *ll_dest, const void *ll_source ); +extern void net_poll ( void ); /** * Complete network transmission @@ -585,4 +600,24 @@ netdev_link_up ( struct net_device *netdev ) { netdev_link_err ( netdev, 0 ); } +/** + * Freeze network device receive queue processing + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_rx_freeze ( struct net_device *netdev ) { + netdev->state |= NETDEV_RX_FROZEN; +} + +/** + * Unfreeze network device receive queue processing + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_rx_unfreeze ( struct net_device *netdev ) { + netdev->state &= ~NETDEV_RX_FROZEN; +} + #endif /* _IPXE_NETDEVICE_H */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index c6c377b5..90dab8fb 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -669,14 +669,12 @@ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, } /** - * Single-step the network stack - * - * @v process Network stack process + * Poll the network stack * * This polls all interfaces for received packets, and processes * packets from the RX queue. */ -static void net_step ( struct process *process __unused ) { +void net_poll ( void ) { struct net_device *netdev; struct io_buffer *iobuf; struct ll_protocol *ll_protocol; @@ -691,6 +689,15 @@ static void net_step ( struct process *process __unused ) { /* Poll for new packets */ netdev_poll ( netdev ); + /* Leave received packets on the queue if receive + * queue processing is currently frozen. This will + * happen when the raw packets are to be manually + * dequeued using netdev_rx_dequeue(), rather than + * processed via the usual networking stack. + */ + if ( netdev_rx_frozen ( netdev ) ) + continue; + /* Process at most one received packet. Give priority * to getting packets out of the NIC over processing * the received packets, because we advertise a window @@ -723,6 +730,15 @@ static void net_step ( struct process *process __unused ) { } } +/** + * Single-step the network stack + * + * @v process Network stack process + */ +static void net_step ( struct process *process __unused ) { + net_poll(); +} + /** Networking stack process */ struct process net_process __permanent_process = { .list = LIST_HEAD_INIT ( net_process.list ), From 69d1e6cf57994882791109390bbe5a7b0b785c1e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 20 Nov 2010 16:47:49 +0000 Subject: [PATCH 13/85] [pxe] Use network device receive queue freezing Signed-off-by: Michael Brown --- src/arch/i386/interface/pxe/pxe_undi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/arch/i386/interface/pxe/pxe_undi.c b/src/arch/i386/interface/pxe/pxe_undi.c index 27f3c801..fdc6f3e2 100644 --- a/src/arch/i386/interface/pxe/pxe_undi.c +++ b/src/arch/i386/interface/pxe/pxe_undi.c @@ -58,8 +58,10 @@ struct net_device *pxe_netdev = NULL; * @v netdev Network device, or NULL */ void pxe_set_netdev ( struct net_device *netdev ) { - if ( pxe_netdev ) + if ( pxe_netdev ) { + netdev_rx_unfreeze ( pxe_netdev ); netdev_put ( pxe_netdev ); + } pxe_netdev = NULL; if ( netdev ) pxe_netdev = netdev_get ( netdev ); @@ -76,6 +78,7 @@ static int pxe_netdev_open ( void ) { if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 ) return rc; + netdev_rx_freeze ( pxe_netdev ); netdev_irq ( pxe_netdev, 1 ); return 0; } @@ -85,6 +88,7 @@ static int pxe_netdev_open ( void ) { * */ static void pxe_netdev_close ( void ) { + netdev_rx_unfreeze ( pxe_netdev ); netdev_irq ( pxe_netdev, 0 ); netdev_close ( pxe_netdev ); undi_tx_count = 0; @@ -234,10 +238,11 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT DBG2 ( "PXENV_UNDI_TRANSMIT" ); - /* Forcibly enable interrupts at this point, to work around - * callers that never call PXENV_UNDI_OPEN before attempting - * to use the UNDI API. + /* Forcibly enable interrupts and freeze receive queue + * processing at this point, to work around callers that never + * call PXENV_UNDI_OPEN before attempting to use the UNDI API. */ + netdev_rx_freeze ( pxe_netdev ); netdev_irq ( pxe_netdev, 1 ); /* Identify network-layer protocol */ @@ -670,7 +675,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { /* Call poll(). This should acknowledge the device * interrupt and queue up any received packet. */ - netdev_poll ( pxe_netdev ); + net_poll(); /* A 100% accurate determination of "OURS" vs "NOT * OURS" is difficult to achieve without invasive and @@ -709,7 +714,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to * cope with these out-of-spec clients. */ - netdev_poll ( pxe_netdev ); + net_poll(); /* If we have not yet marked a TX as complete, and the * netdev TX queue is empty, report the TX completion. From 3633bb246cf0ba420322a507989ec6031375075e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 20 Nov 2010 05:03:06 +0000 Subject: [PATCH 14/85] [lotest] Use network device receive queue freezing Signed-off-by: Michael Brown --- src/usr/lotest.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/usr/lotest.c b/src/usr/lotest.c index 407f6844..6c87923c 100644 --- a/src/usr/lotest.c +++ b/src/usr/lotest.c @@ -119,6 +119,11 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, ifstat ( sender ); ifstat ( receiver ); + /* Freeze receive queue processing on the receiver, so that we + * can extract all received packets. + */ + netdev_rx_freeze ( receiver ); + /* Perform loopback test */ for ( successes = 0 ; ; successes++ ) { @@ -155,8 +160,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, goto done; } /* Poll network devices */ - netdev_poll ( sender ); - netdev_poll ( receiver ); + net_poll(); } while ( ( iobuf = netdev_rx_dequeue ( receiver ) ) == NULL ); /* Check received packet */ @@ -203,6 +207,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, done: printf ( "\n"); free_iob ( iobuf ); + netdev_rx_unfreeze ( receiver ); /* Dump final statistics */ ifstat ( sender ); From f12fcd53b1b661b5bfe7b5048398225297133b95 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 20 Nov 2010 05:08:25 +0000 Subject: [PATCH 15/85] [lotest] Fix endianness in status message Signed-off-by: Michael Brown --- src/usr/lotest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/lotest.c b/src/usr/lotest.c index 6c87923c..c8ee6213 100644 --- a/src/usr/lotest.c +++ b/src/usr/lotest.c @@ -194,7 +194,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, } } else { printf ( "\nReceived spurious packet type %04x\n", - net_proto ); + ntohs ( net_proto ) ); /* Continue; this allows for the fact that * there may have been packets outstanding on * the wire when we started the test. From 6fd09b541fbc426057661c7e0da4f39000b6803e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Nov 2010 00:23:26 +0000 Subject: [PATCH 16/85] [vlan] Add support for IEEE 802.1Q VLANs Originally-implemented-by: michael-dev@fami-braun.de Signed-off-by: Michael Brown --- src/config/config.c | 3 + src/config/general.h | 1 + src/hci/commands/vlan_cmd.c | 174 +++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/features.h | 1 + src/include/ipxe/if_ether.h | 1 + src/include/ipxe/netdevice.h | 11 +- src/include/ipxe/vlan.h | 66 +++++ src/net/netdevice.c | 12 +- src/net/vlan.c | 465 +++++++++++++++++++++++++++++++++++ 10 files changed, 725 insertions(+), 10 deletions(-) create mode 100644 src/hci/commands/vlan_cmd.c create mode 100644 src/include/ipxe/vlan.h create mode 100644 src/net/vlan.c diff --git a/src/config/config.c b/src/config/config.c index f9061d06..5d218881 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -234,6 +234,9 @@ REQUIRE_OBJECT ( pxe_cmd ); #ifdef LOTEST_CMD REQUIRE_OBJECT ( lotest_cmd ); #endif +#ifdef VLAN_CMD +REQUIRE_OBJECT ( vlan_cmd ); +#endif /* * Drag in miscellaneous objects diff --git a/src/config/general.h b/src/config/general.h index 652ecf75..b84707ab 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -123,6 +123,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #undef TIME_CMD /* Time commands */ #undef DIGEST_CMD /* Image crypto digest commands */ #undef LOTEST_CMD /* Loopback testing commands */ +#undef VLAN_CMD /* VLAN commands */ //#undef PXE_CMD /* PXE commands */ /* diff --git a/src/hci/commands/vlan_cmd.c b/src/hci/commands/vlan_cmd.c new file mode 100644 index 00000000..d9e411fb --- /dev/null +++ b/src/hci/commands/vlan_cmd.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * VLAN commands + * + */ + +static void vcreate_syntax ( char **argv ) { + printf ( "Usage:\n %s --tag [--priority \n", argv[0] ); +} + +static int vcreate_exec ( int argc, char **argv ) { + static struct option vcreate_opts[] = { + { "help", 0, NULL, 'h' }, + { "tag", required_argument, NULL, 't' }, + { "priority", required_argument, NULL, 'p' }, + { NULL, 0, NULL, 0 }, + }; + const char *trunk_name; + const char *tag_text = NULL; + const char *priority_text = NULL; + struct net_device *trunk; + unsigned int tag; + unsigned int priority; + char *endp; + int c; + int rc; + + /* Parse command line */ + while ( ( c = getopt_long ( argc, argv, "ht:p:", vcreate_opts, + NULL ) ) >= 0 ) { + switch ( c ) { + case 't': + tag_text = optarg; + break; + case 'p': + priority_text = optarg; + break; + case 'h': + /* Display help text */ + default: + /* Unrecognised/invalid option */ + vcreate_syntax ( argv ); + return 1; + } + } + if ( optind != ( argc - 1 ) ) { + vcreate_syntax ( argv ); + return 1; + } + trunk_name = argv[optind]; + if ( ! tag_text ) { + vcreate_syntax ( argv ); + return 1; + } + + /* Identify network device */ + trunk = find_netdev ( trunk_name ); + if ( ! trunk ) { + printf ( "%s: no such interface\n", trunk_name ); + return 1; + } + tag = strtoul ( tag_text, &endp, 10 ); + if ( *endp ) { + printf ( "%s: invalid tag\n", tag_text ); + return 1; + } + if ( priority_text ) { + priority = strtoul ( priority_text, &endp, 10 ); + if ( *endp ) { + printf ( "%s: invalid priority\n", priority_text ); + return 1; + } + } else { + priority = 0; + } + + /* Create VLAN device */ + if ( ( rc = vlan_create ( trunk, tag, priority ) ) != 0 ) { + printf ( "Could not create VLAN device: %s\n", + strerror ( rc ) ); + return 1; + } + + return 0; +} + +static void vdestroy_syntax ( char **argv ) { + printf ( "Usage:\n %s \n", argv[0] ); +} + +static int vdestroy_exec ( int argc, char **argv ) { + static struct option vdestroy_opts[] = { + { "help", 0, NULL, 'h' }, + { NULL, 0, NULL, 0 }, + }; + const char *netdev_name; + struct net_device *netdev; + int c; + int rc; + + /* Parse command line */ + while ( ( c = getopt_long ( argc, argv, "h", vdestroy_opts, + NULL ) ) >= 0 ) { + switch ( c ) { + case 'h': + /* Display help text */ + default: + /* Unrecognised/invalid option */ + vdestroy_syntax ( argv ); + return 1; + } + } + if ( optind != ( argc - 1 ) ) { + vdestroy_syntax ( argv ); + return 1; + } + netdev_name = argv[optind]; + + /* Identify network device */ + netdev = find_netdev ( netdev_name ); + if ( ! netdev ) { + printf ( "%s: no such interface\n", netdev_name ); + return 1; + } + + /* Destroy VLAN device */ + if ( ( rc = vlan_destroy ( netdev ) ) != 0 ) { + printf ( "Could not destroy VLAN device: %s\n", + strerror ( rc ) ); + return 1; + } + + return 0; +} + +struct command vlan_commands[] __command = { + { + .name = "vcreate", + .exec = vcreate_exec, + }, + { + .name = "vdestroy", + .exec = vdestroy_exec, + }, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 2255f8a3..5f0f1661 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -190,6 +190,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_fcp ( ERRFILE_NET | 0x002d0000 ) #define ERRFILE_fcoe ( ERRFILE_NET | 0x002e0000 ) #define ERRFILE_fcns ( ERRFILE_NET | 0x002f0000 ) +#define ERRFILE_vlan ( ERRFILE_NET | 0x00300000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/include/ipxe/features.h b/src/include/ipxe/features.h index 76b59321..660015cd 100644 --- a/src/include/ipxe/features.h +++ b/src/include/ipxe/features.h @@ -51,6 +51,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define DHCP_EB_FEATURE_COMBOOT 0x23 /**< COMBOOT format */ #define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */ #define DHCP_EB_FEATURE_FCOE 0x25 /**< FCoE protocol */ +#define DHCP_EB_FEATURE_VLAN 0x26 /**< VLAN support */ /** @} */ diff --git a/src/include/ipxe/if_ether.h b/src/include/ipxe/if_ether.h index db6cb0df..a7e23734 100644 --- a/src/include/ipxe/if_ether.h +++ b/src/include/ipxe/if_ether.h @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ETH_P_IP 0x0800 /* Internet Protocl Packet */ #define ETH_P_ARP 0x0806 /* Address Resolution Protocol */ #define ETH_P_RARP 0x8035 /* Reverse Address resolution Protocol */ +#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ #define ETH_P_IPV6 0x86DD /* IPv6 over blueblook */ #define ETH_P_SLOW 0x8809 /* Ethernet slow protocols */ #define ETH_P_EAPOL 0x888E /* 802.1X EAP over LANs */ diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index 26e2ab89..6986233e 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -36,11 +36,12 @@ struct device; /** Maximum length of a link-layer header * * The longest currently-supported link-layer header is for 802.11: a - * 24-byte frame header plus an 8-byte 802.3 LLC/SNAP header. (The - * IPoIB link-layer pseudo-header doesn't actually include link-layer - * addresses; see ipoib.c for details). + * 24-byte frame header plus an 8-byte 802.3 LLC/SNAP header, plus a + * possible 4-byte VLAN header. (The IPoIB link-layer pseudo-header + * doesn't actually include link-layer addresses; see ipoib.c for + * details.) */ -#define MAX_LL_HEADER_LEN 32 +#define MAX_LL_HEADER_LEN 36 /** Maximum length of a network-layer address */ #define MAX_NET_ADDR_LEN 4 @@ -278,7 +279,7 @@ struct net_device { /** List of open network devices */ struct list_head open_list; /** Name of this network device */ - char name[8]; + char name[12]; /** Underlying hardware device */ struct device *dev; diff --git a/src/include/ipxe/vlan.h b/src/include/ipxe/vlan.h new file mode 100644 index 00000000..86d78bed --- /dev/null +++ b/src/include/ipxe/vlan.h @@ -0,0 +1,66 @@ +#ifndef _IPXE_VLAN_H +#define _IPXE_VLAN_H + +/** + * @file + * + * Virtual LANs + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** A VLAN header */ +struct vlan_header { + /** Tag control information */ + uint16_t tci; + /** Encapsulated protocol */ + uint16_t net_proto; +} __attribute__ (( packed )); + +/** + * Extract VLAN tag from tag control information + * + * @v tci Tag control information + * @ret tag VLAN tag + */ +#define VLAN_TAG( tci ) ( (tci) & 0x0fff ) + +/** + * Extract VLAN priority from tag control information + * + * @v tci Tag control information + * @ret priority Priority + */ +#define VLAN_PRIORITY( tci ) ( (tci) >> 13 ) + +/** + * Construct VLAN tag control information + * + * @v tag VLAN tag + * @v priority Priority + * @ret tci Tag control information + */ +#define VLAN_TCI( tag, priority ) ( ( (priority) << 13 ) | (tag) ) + +/** + * Check VLAN tag is valid + * + * @v tag VLAN tag + * @ret is_valid VLAN tag is valid + */ +#define VLAN_TAG_IS_VALID( tag ) ( ( (tag) >= 1 ) && ( (tag) < 0xfff ) ) + +/** + * Check VLAN priority is valid + * + * @v priority VLAN priority + * @ret is_valid VLAN priority is valid + */ +#define VLAN_PRIORITY_IS_VALID( priority ) ( (priority) <= 7 ) + +extern int vlan_create ( struct net_device *trunk, unsigned int tag, + unsigned int priority ); +extern int vlan_destroy ( struct net_device *netdev ); + +#endif /* _IPXE_VLAN_H */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 90dab8fb..37887073 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -405,8 +405,10 @@ int register_netdev ( struct net_device *netdev ) { int rc; /* Create device name */ - snprintf ( netdev->name, sizeof ( netdev->name ), "net%d", - ifindex++ ); + if ( netdev->name[0] == '\0' ) { + snprintf ( netdev->name, sizeof ( netdev->name ), "net%d", + ifindex++ ); + } /* Set initial link-layer address */ netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); @@ -461,13 +463,13 @@ int netdev_open ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %s opening\n", netdev->name ); + /* Mark as opened */ + netdev->state |= NETDEV_OPEN; + /* Open the device */ if ( ( rc = netdev->op->open ( netdev ) ) != 0 ) return rc; - /* Mark as opened */ - netdev->state |= NETDEV_OPEN; - /* Add to head of open devices list */ list_add ( &netdev->open_list, &open_net_devices ); diff --git a/src/net/vlan.c b/src/net/vlan.c new file mode 100644 index 00000000..a764f305 --- /dev/null +++ b/src/net/vlan.c @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Virtual LANs + * + */ + +FEATURE ( FEATURE_PROTOCOL, "VLAN", DHCP_EB_FEATURE_VLAN, 1 ); + +struct net_protocol vlan_protocol __net_protocol; + +/** VLAN device private data */ +struct vlan_device { + /** Trunk network device */ + struct net_device *trunk; + /** VLAN tag */ + unsigned int tag; + /** Default priority */ + unsigned int priority; +}; + +/** + * Open VLAN device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int vlan_open ( struct net_device *netdev ) { + struct vlan_device *vlan = netdev->priv; + + return netdev_open ( vlan->trunk ); +} + +/** + * Close VLAN device + * + * @v netdev Network device + */ +static void vlan_close ( struct net_device *netdev ) { + struct vlan_device *vlan = netdev->priv; + + netdev_close ( vlan->trunk ); +} + +/** + * Transmit packet on VLAN device + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int vlan_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct vlan_device *vlan = netdev->priv; + struct net_device *trunk = vlan->trunk; + struct ll_protocol *ll_protocol; + struct vlan_header *vlanhdr; + uint8_t ll_dest_copy[ETH_ALEN]; + uint8_t ll_source_copy[ETH_ALEN]; + const void *ll_dest; + const void *ll_source; + uint16_t net_proto; + int rc; + + /* Strip link-layer header and preserve link-layer header fields */ + ll_protocol = netdev->ll_protocol; + if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source, + &net_proto ) ) != 0 ) { + DBGC ( netdev, "VLAN %s could not parse link-layer header: " + "%s\n", netdev->name, strerror ( rc ) ); + return rc; + } + memcpy ( ll_dest_copy, ll_dest, ETH_ALEN ); + memcpy ( ll_source_copy, ll_source, ETH_ALEN ); + + /* Construct VLAN header */ + vlanhdr = iob_push ( iobuf, sizeof ( *vlanhdr ) ); + vlanhdr->tci = htons ( VLAN_TCI ( vlan->tag, vlan->priority ) ); + vlanhdr->net_proto = net_proto; + + /* Reclaim I/O buffer from VLAN device's TX queue */ + list_del ( &iobuf->list ); + + /* Transmit packet on trunk device */ + if ( ( rc = net_tx ( iob_disown ( iobuf ), trunk, &vlan_protocol, + ll_dest_copy, ll_source_copy ) ) != 0 ) { + DBGC ( netdev, "VLAN %s could not transmit: %s\n", + netdev->name, strerror ( rc ) ); + /* Cannot return an error status, since that would + * cause the I/O buffer to be double-freed. + */ + return 0; + } + + return 0; +} + +/** + * Poll VLAN device + * + * @v netdev Network device + */ +static void vlan_poll ( struct net_device *netdev ) { + struct vlan_device *vlan = netdev->priv; + + /* Poll trunk device */ + netdev_poll ( vlan->trunk ); +} + +/** + * Enable/disable interrupts on VLAN device + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void vlan_irq ( struct net_device *netdev, int enable ) { + struct vlan_device *vlan = netdev->priv; + + /* Enable/disable interrupts on trunk device. This is not at + * all robust, but there is no sensible course of action + * available. + */ + netdev_irq ( vlan->trunk, enable ); +} + +/** VLAN device operations */ +static struct net_device_operations vlan_operations = { + .open = vlan_open, + .close = vlan_close, + .transmit = vlan_transmit, + .poll = vlan_poll, + .irq = vlan_irq, +}; + +/** + * Synchronise VLAN device + * + * @v netdev Network device + */ +static void vlan_sync ( struct net_device *netdev ) { + struct vlan_device *vlan = netdev->priv; + struct net_device *trunk = vlan->trunk; + + /* Synchronise link status */ + if ( netdev->link_rc != trunk->link_rc ) + netdev_link_err ( netdev, trunk->link_rc ); + + /* Synchronise open/closed status */ + if ( netdev_is_open ( trunk ) ) { + if ( ! netdev_is_open ( netdev ) ) + netdev_open ( netdev ); + } else { + if ( netdev_is_open ( netdev ) ) + netdev_close ( netdev ); + } +} + +/** + * Identify VLAN device + * + * @v trunk Trunk network device + * @v tag VLAN tag + * @ret netdev VLAN device, if any + */ +static struct net_device * vlan_find ( struct net_device *trunk, + uint16_t tag ) { + struct net_device *netdev; + struct vlan_device *vlan; + + for_each_netdev ( netdev ) { + if ( netdev->op != &vlan_operations ) + continue; + vlan = netdev->priv; + if ( ( vlan->trunk == trunk ) && ( vlan->tag == tag ) ) + return netdev; + } + return NULL; +} + +/** + * Process incoming VLAN packet + * + * @v iobuf I/O buffer + * @v trunk Trunk network device + * @v ll_dest Link-layer destination address + * @v ll_source Link-layer source address + * @ret rc Return status code + */ +static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk, + const void *ll_dest, const void *ll_source ) { + struct vlan_header *vlanhdr = iobuf->data; + struct net_device *netdev; + struct ll_protocol *ll_protocol; + uint8_t ll_dest_copy[ETH_ALEN]; + uint8_t ll_source_copy[ETH_ALEN]; + uint16_t tag; + int rc; + + /* Sanity check */ + if ( iob_len ( iobuf ) < sizeof ( *vlanhdr ) ) { + DBGC ( trunk, "VLAN %s received underlength packet (%zd " + "bytes)\n", trunk->name, iob_len ( iobuf ) ); + rc = -EINVAL; + goto err_sanity; + } + + /* Identify VLAN device */ + tag = VLAN_TAG ( ntohs ( vlanhdr->tci ) ); + netdev = vlan_find ( trunk, tag ); + if ( ! netdev ) { + DBGC2 ( trunk, "VLAN %s received packet for unknown VLAN " + "%d\n", trunk->name, tag ); + rc = -EPIPE; + goto err_no_vlan; + } + + /* Strip VLAN header and preserve original link-layer header fields */ + iob_pull ( iobuf, sizeof ( *vlanhdr ) ); + ll_protocol = trunk->ll_protocol; + memcpy ( ll_dest_copy, ll_dest, ETH_ALEN ); + memcpy ( ll_source_copy, ll_source, ETH_ALEN ); + + /* Reconstruct link-layer header for VLAN device */ + ll_protocol = netdev->ll_protocol; + if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest_copy, + ll_source_copy, + vlanhdr->net_proto ) ) != 0 ) { + DBGC ( netdev, "VLAN %s could not reconstruct link-layer " + "header: %s\n", netdev->name, strerror ( rc ) ); + goto err_ll_push; + } + + /* Enqueue packet on VLAN device */ + netdev_rx ( netdev, iob_disown ( iobuf ) ); + return 0; + + err_ll_push: + err_no_vlan: + err_sanity: + free_iob ( iobuf ); + return rc; +} + +/** VLAN protocol */ +struct net_protocol vlan_protocol __net_protocol = { + .name = "VLAN", + .net_proto = htons ( ETH_P_8021Q ), + .rx = vlan_rx, +}; + +/** + * Create VLAN device + * + * @v trunk Trunk network device + * @v tag VLAN tag + * @v priority Default VLAN priority + * @ret rc Return status code + * + * The VLAN device will be created as an Ethernet device. (We cannot + * simply clone the link layer of the trunk network device, because + * this link layer may expect the network device structure to contain + * some link-layer-private data.) The trunk network device must + * therefore have a link layer that is in some sense 'compatible' with + * Ethernet; specifically, it must have link-layer addresses that are + * the same length as Ethernet link-layer addresses. + */ +int vlan_create ( struct net_device *trunk, unsigned int tag, + unsigned int priority ) { + struct net_device *netdev; + struct vlan_device *vlan; + int rc; + + /* Sanity checks */ + if ( trunk->ll_protocol->ll_addr_len != ETH_ALEN ) { + DBGC ( trunk, "VLAN %s cannot create VLAN for %s device\n", + trunk->name, trunk->ll_protocol->name ); + rc = -ENOTTY; + goto err_sanity; + } + if ( ! VLAN_TAG_IS_VALID ( tag ) ) { + DBGC ( trunk, "VLAN %s cannot create VLAN with invalid tag " + "%d\n", trunk->name, tag ); + rc = -EINVAL; + goto err_sanity; + } + if ( ! VLAN_PRIORITY_IS_VALID ( priority ) ) { + DBGC ( trunk, "VLAN %s cannot create VLAN with invalid " + "priority %d\n", trunk->name, priority ); + rc = -EINVAL; + goto err_sanity; + } + if ( ( netdev = vlan_find ( trunk, tag ) ) != NULL ) { + DBGC ( netdev, "VLAN %s already exists\n", netdev->name ); + rc = -EEXIST; + goto err_sanity; + } + + /* Allocate and initialise structure */ + netdev = alloc_etherdev ( sizeof ( *vlan ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc_etherdev; + } + netdev_init ( netdev, &vlan_operations ); + netdev->dev = trunk->dev; + memcpy ( netdev->hw_addr, trunk->ll_addr, ETH_ALEN ); + vlan = netdev->priv; + vlan->trunk = netdev_get ( trunk ); + vlan->tag = tag; + vlan->priority = priority; + + /* Construct VLAN device name */ + snprintf ( netdev->name, sizeof ( netdev->name ), "%s.%d", + trunk->name, vlan->tag ); + + /* Register VLAN device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) { + DBGC ( netdev, "VLAN %s could not register: %s\n", + netdev->name, strerror ( rc ) ); + goto err_register; + } + + /* Synchronise with trunk device */ + vlan_sync ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + netdev_put ( trunk ); + err_alloc_etherdev: + err_sanity: + return rc; +} + +/** + * Destroy VLAN device + * + * @v netdev Network device + * @ret rc Return status code + */ +int vlan_destroy ( struct net_device *netdev ) { + struct vlan_device *vlan = netdev->priv; + struct net_device *trunk; + + /* Sanity check */ + if ( netdev->op != &vlan_operations ) { + DBGC ( netdev, "VLAN %s cannot destroy non-VLAN device\n", + netdev->name ); + return -ENOTTY; + } + + /* Remove VLAN device */ + unregister_netdev ( netdev ); + trunk = vlan->trunk; + netdev_nullify ( netdev ); + netdev_put ( netdev ); + netdev_put ( trunk ); + + return 0; +} + +/** + * Do nothing + * + * @v trunk Trunk network device + * @ret rc Return status code + */ +static int vlan_probe ( struct net_device *trunk __unused ) { + return 0; +} + +/** + * Handle trunk network device link state change + * + * @v trunk Trunk network device + */ +static void vlan_notify ( struct net_device *trunk ) { + struct net_device *netdev; + struct vlan_device *vlan; + + for_each_netdev ( netdev ) { + if ( netdev->op != &vlan_operations ) + continue; + vlan = netdev->priv; + if ( vlan->trunk == trunk ) + vlan_sync ( netdev ); + } +} + +/** + * Destroy first VLAN device for a given trunk + * + * @v trunk Trunk network device + * @ret found A VLAN device was found + */ +static int vlan_remove_first ( struct net_device *trunk ) { + struct net_device *netdev; + struct vlan_device *vlan; + + for_each_netdev ( netdev ) { + if ( netdev->op != &vlan_operations ) + continue; + vlan = netdev->priv; + if ( vlan->trunk == trunk ) { + vlan_destroy ( netdev ); + return 1; + } + } + return 0; +} + +/** + * Destroy all VLAN devices for a given trunk + * + * @v trunk Trunk network device + */ +static void vlan_remove ( struct net_device *trunk ) { + + /* Remove all VLAN devices attached to this trunk, safe + * against arbitrary net device removal. + */ + while ( vlan_remove_first ( trunk ) ) {} +} + +/** VLAN driver */ +struct net_driver vlan_driver __net_driver = { + .name = "VLAN", + .probe = vlan_probe, + .notify = vlan_notify, + .remove = vlan_remove, +}; From 44482851427e26ba6f77485064ef7217b632daac Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 20 Nov 2010 17:20:03 +0000 Subject: [PATCH 17/85] [autoboot] Add "netboot" command Originally-implemented-by: michael-dev@fami-braun.de Signed-off-by: Michael Brown --- src/hci/commands/autoboot_cmd.c | 39 ++++++++++++++++++++++++++++++--- src/include/usr/autoboot.h | 1 + src/usr/autoboot.c | 2 +- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/hci/commands/autoboot_cmd.c b/src/hci/commands/autoboot_cmd.c index 51ba6f1f..17bd6bcf 100644 --- a/src/hci/commands/autoboot_cmd.c +++ b/src/hci/commands/autoboot_cmd.c @@ -1,5 +1,6 @@ #include #include +#include #include FILE_LICENCE ( GPL2_OR_LATER ); @@ -21,7 +22,39 @@ static int autoboot_exec ( int argc, char **argv ) { return 1; } -struct command autoboot_command __command = { - .name = "autoboot", - .exec = autoboot_exec, +static int netboot_exec ( int argc, char **argv ) { + const char *netdev_name; + struct net_device *netdev; + + if ( argc != 2 ) { + printf ( "Usage:\n" + " %s \n" + "\n" + "Attempts to boot the system from \n", + argv[0] ); + return 1; + } + netdev_name = argv[1]; + + netdev = find_netdev ( netdev_name ); + if ( ! netdev ) { + printf ( "%s: no such interface\n", netdev_name ); + return 1; + } + + netboot ( netdev ); + + /* Can never return success by definition */ + return 1; +} + +struct command autoboot_commands[] __command = { + { + .name = "autoboot", + .exec = autoboot_exec, + }, + { + .name = "netboot", + .exec = netboot_exec, + }, }; diff --git a/src/include/usr/autoboot.h b/src/include/usr/autoboot.h index 81b686b5..46e3b481 100644 --- a/src/include/usr/autoboot.h +++ b/src/include/usr/autoboot.h @@ -14,6 +14,7 @@ struct net_device; extern int shutdown_exit_flags; +extern int netboot ( struct net_device *netdev ); extern void autoboot ( void ); extern int boot_next_server_and_filename ( struct in_addr next_server, const char *filename ); diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index 4e8db60e..d87e3627 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -220,7 +220,7 @@ int boot_root_path ( const char *root_path ) { * @v netdev Network device * @ret rc Return status code */ -static int netboot ( struct net_device *netdev ) { +int netboot ( struct net_device *netdev ) { struct setting vendor_class_id_setting = { .tag = DHCP_VENDOR_CLASS_ID }; struct setting pxe_discovery_control_setting From 216fd0a5cf3f017a19f5ad0006011637dcfa9a5b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 15:58:30 +0000 Subject: [PATCH 18/85] [parseopt] Add generic option-parsing library Command implementations tend to include a substantial amount of common boilerplate code revolving around the parsing of command-line options and arguments. This increases the size cost of each command. Introduce an option-parsing library that abstracts out the common operations involved in command implementations. This enables the size of each individual command to be reduced, and also enhances consistency between commands. Total size of the library is 704 bytes, to be amortised across all command implementations. Signed-off-by: Michael Brown --- src/core/parseopt.c | 219 ++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/parseopt.h | 127 +++++++++++++++++++++ 3 files changed, 347 insertions(+) create mode 100644 src/core/parseopt.c create mode 100644 src/include/ipxe/parseopt.h diff --git a/src/core/parseopt.c b/src/core/parseopt.c new file mode 100644 index 00000000..ccaed374 --- /dev/null +++ b/src/core/parseopt.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Command line option parsing + * + */ + +/** Return status code for "--help" option */ +#define ECANCELED_NO_OP __einfo_error ( EINFO_ECANCELED_NO_OP ) +#define EINFO_ECANCELED_NO_OP \ + __einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" ) + +/** +* Parse string value + * + * @v text Text + * @ret value String value + * @ret rc Return status code + */ +int parse_string ( const char *text, const char **value ) { + + /* Sanity check */ + assert ( text != NULL ); + + /* Parse string */ + *value = text; + + return 0; +} + +/** + * Parse integer value + * + * @v text Text + * @ret value Integer value + * @ret rc Return status code + */ +int parse_integer ( const char *text, unsigned int *value ) { + char *endp; + + /* Sanity check */ + assert ( text != NULL ); + + /* Parse integer */ + *value = strtoul ( text, &endp, 10 ); + if ( *endp ) { + printf ( "\"%s\": invalid integer value\n", text ); + return -EINVAL; + } + + return 0; +} + +/** + * Parse network device name + * + * @v text Text + * @ret netdev Network device + * @ret rc Return status code + */ +int parse_netdev ( const char *text, struct net_device **netdev ) { + + /* Sanity check */ + assert ( text != NULL ); + + /* Find network device */ + *netdev = find_netdev ( text ); + if ( ! *netdev ) { + printf ( "\"%s\": no such network device\n", text ); + return -ENODEV; + } + + return 0; +} + +/** + * Parse image name + * + * @v text Text + * @ret image Image + * @ret rc Return status code + */ +int parse_image ( const char *text, struct image **image ) { + + /* Sanity check */ + assert ( text != NULL ); + + /* Find network device */ + *image = find_image ( text ); + if ( ! *image ) { + printf ( "\"%s\": no such image\n", text ); + return -ENOENT; + } + + return 0; +} + +/** + * Print command usage message + * + * @v cmd Command descriptor + * @v argv Argument list + */ +void print_usage ( struct command_descriptor *cmd, char **argv ) { + printf ( "Usage:\n\n %s %s\n", argv[0], cmd->usage_description ); +} + +/** + * Parse command-line options + * + * @v argc Argument count + * @v argv Argument list + * @v cmd Command descriptor + * @v opts Options + * @ret rc Return status code + */ +int parse_options ( int argc, char **argv, struct command_descriptor *cmd, + void *opts ) { + struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ]; + char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */ + + 1 /* NUL */ ]; + unsigned int shortopt_idx = 0; + int ( * parse ) ( const char *text, void *value ); + void *value; + unsigned int i; + unsigned int j; + unsigned int num_args; + int c; + int rc; + + /* Construct long and short option lists for getopt_long() */ + memset ( longopts, 0, sizeof ( longopts ) ); + for ( i = 0 ; i < cmd->num_options ; i++ ) { + longopts[i].name = cmd->options[i].longopt; + longopts[i].has_arg = cmd->options[i].has_arg; + longopts[i].val = cmd->options[i].shortopt; + shortopts[shortopt_idx++] = cmd->options[i].shortopt; + assert ( cmd->options[i].has_arg <= optional_argument ); + for ( j = cmd->options[i].has_arg ; j > 0 ; j-- ) + shortopts[shortopt_idx++] = ':'; + } + longopts[i].name = "help"; + longopts[i].val = 'h'; + shortopts[shortopt_idx++] = 'h'; + shortopts[shortopt_idx++] = '\0'; + assert ( shortopt_idx <= sizeof ( shortopts ) ); + DBGC ( cmd, "Command \"%s\" has options \"%s\", %d-%d args, len %d\n", + argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len ); + + /* Clear options */ + memset ( opts, 0, cmd->len ); + + /* Parse options */ + while ( ( c = getopt_long ( argc, argv, shortopts, longopts, + NULL ) ) >= 0 ) { + switch ( c ) { + case 'h' : + /* Print help */ + print_usage ( cmd, argv ); + return -ECANCELED_NO_OP; + case '?' : + case ':' : + /* Print usage message */ + print_usage ( cmd, argv ); + return -EINVAL; + default: + /* Search for an option to parse */ + for ( i = 0 ; i < cmd->num_options ; i++ ) { + if ( c != cmd->options[i].shortopt ) + continue; + parse = cmd->options[i].parse; + value = ( opts + cmd->options[i].offset ); + if ( ( rc = parse ( optarg, value ) ) != 0 ) + return rc; + break; + } + assert ( i < cmd->num_options ); + } + } + + /* Check remaining arguments */ + num_args = ( argc - optind ); + if ( ( num_args < cmd->min_args ) || ( num_args > cmd->max_args ) ) { + print_usage ( cmd, argv ); + return -ERANGE; + } + + return 0; +} diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 5f0f1661..7b415928 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -59,6 +59,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_acpi ( ERRFILE_CORE | 0x00130000 ) #define ERRFILE_null_sanboot ( ERRFILE_CORE | 0x00140000 ) #define ERRFILE_edd ( ERRFILE_CORE | 0x00150000 ) +#define ERRFILE_parseopt ( ERRFILE_CORE | 0x00160000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) diff --git a/src/include/ipxe/parseopt.h b/src/include/ipxe/parseopt.h new file mode 100644 index 00000000..f949b4cc --- /dev/null +++ b/src/include/ipxe/parseopt.h @@ -0,0 +1,127 @@ +#ifndef _IPXE_PARSEOPT_H +#define _IPXE_PARSEOPT_H + +/** @file + * + * Command line option parsing + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +struct net_device; +struct image; + +/** A command-line option descriptor */ +struct option_descriptor { + /** Long option name, if any */ + const char *longopt; + /** Short option name */ + char shortopt; + /** Argument requirement (as for @c struct @c option) */ + uint8_t has_arg; + /** Offset of field within options structure */ + uint16_t offset; + /** Parse option + * + * @v text Option text + * @v value Option value to fill in + * @ret rc Return status code + */ + int ( * parse ) ( const char *text, void *value ); +}; + +/** + * Construct option parser + * + * @v _struct Options structure type + * @v _field Field within options structure + * @v _parse Field type-specific option parser + * @ret _parse Generic option parser + */ +#define OPTION_PARSER( _struct, _field, _parse ) \ + ( ( int ( * ) ( const char *text, void *value ) ) \ + ( ( ( ( typeof ( _parse ) * ) NULL ) == \ + ( ( int ( * ) ( const char *text, \ + typeof ( ( ( _struct * ) NULL )->_field ) * ) ) \ + NULL ) ) ? _parse : _parse ) ) + +/** + * Construct option descriptor + * + * @v _longopt Long option name, if any + * @v _shortopt Short option name, if any + * @v _has_arg Argument requirement + * @v _struct Options structure type + * @v _field Field within options structure + * @v _parse Field type-specific option parser + * @ret _option Option descriptor + */ +#define OPTION_DESC( _longopt, _shortopt, _has_arg, _struct, _field, _parse ) \ + { \ + .longopt = _longopt, \ + .shortopt = _shortopt, \ + .has_arg = _has_arg, \ + .offset = offsetof ( _struct, _field ), \ + .parse = OPTION_PARSER ( _struct, _field, _parse ), \ + } + +/** A command descriptor */ +struct command_descriptor { + /** Option descriptors */ + struct option_descriptor *options; + /** Number of option descriptors */ + uint8_t num_options; + /** Length of option structure */ + uint8_t len; + /** Minimum number of non-option arguments */ + uint8_t min_args; + /** Maximum number of non-option arguments */ + uint8_t max_args; + /** Command usage and description + * + * This excludes the literal "Usage:" and the command name, + * which will be prepended automatically. + */ + const char *usage_description; +}; + +/** No maximum number of arguments */ +#define MAX_ARGUMENTS 0xff + +/** + * Construct command descriptor + * + * @v _struct Options structure type + * @v _options Option descriptor array + * @v _check_args Remaining argument checker + * @v _usage Command usage + * @v _description Command description + * @ret _command Command descriptor + */ +#define COMMAND_DESC( _struct, _options, _min_args, _max_args, _usage, \ + _description ) \ + { \ + .options = ( ( ( ( typeof ( _options[0] ) * ) NULL ) == \ + ( ( struct option_descriptor * ) NULL ) ) ? \ + _options : _options ), \ + .num_options = ( sizeof ( _options ) / \ + sizeof ( _options[0] ) ), \ + .len = sizeof ( _struct ), \ + .min_args = _min_args, \ + .max_args = _max_args, \ + .usage_description = _usage "\n\n" _description, \ + } + +extern int parse_string ( const char *text, const char **value ); +extern int parse_integer ( const char *text, unsigned int *value ); +extern int parse_netdev ( const char *text, struct net_device **netdev ); +extern int parse_image ( const char *text, struct image **image ); +extern void print_usage ( struct command_descriptor *cmd, char **argv ); +extern int parse_options ( int argc, char **argv, + struct command_descriptor *cmd, void *opts ); + +#endif /* _IPXE_PARSEOPT_H */ From 2877af3ff585065a3b43630cbfd30ccd4f8d65c9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 16:28:05 +0000 Subject: [PATCH 19/85] [vlan] Use generic option-parsing library Total saving: 261 bytes. Signed-off-by: Michael Brown --- src/hci/commands/vlan_cmd.c | 167 +++++++++++++++--------------------- 1 file changed, 67 insertions(+), 100 deletions(-) diff --git a/src/hci/commands/vlan_cmd.c b/src/hci/commands/vlan_cmd.c index d9e411fb..38a6bab7 100644 --- a/src/hci/commands/vlan_cmd.c +++ b/src/hci/commands/vlan_cmd.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** @file @@ -32,136 +33,102 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -static void vcreate_syntax ( char **argv ) { - printf ( "Usage:\n %s --tag [--priority \n", argv[0] ); -} - -static int vcreate_exec ( int argc, char **argv ) { - static struct option vcreate_opts[] = { - { "help", 0, NULL, 'h' }, - { "tag", required_argument, NULL, 't' }, - { "priority", required_argument, NULL, 'p' }, - { NULL, 0, NULL, 0 }, - }; - const char *trunk_name; - const char *tag_text = NULL; - const char *priority_text = NULL; - struct net_device *trunk; +/** "vcreate" options */ +struct vcreate_options { + /** VLAN tag */ unsigned int tag; + /** VLAN default priority */ unsigned int priority; - char *endp; - int c; +}; + +/** "vcreate" option list */ +static struct option_descriptor vcreate_opts[] = { + OPTION_DESC ( "tag", 't', required_argument, + struct vcreate_options, tag, parse_integer ), + OPTION_DESC ( "priority", 'p', required_argument, + struct vcreate_options, priority, parse_integer ), +}; + +/** "vcreate" command descriptor */ +static struct command_descriptor vcreate_cmd = + COMMAND_DESC ( struct vcreate_options, vcreate_opts, 1, 1, + "--tag [--priority ] " + "", + "Create a VLAN interface" ); + +/** + * "vcreate" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int vcreate_exec ( int argc, char **argv ) { + struct vcreate_options opts; + struct net_device *trunk; int rc; - /* Parse command line */ - while ( ( c = getopt_long ( argc, argv, "ht:p:", vcreate_opts, - NULL ) ) >= 0 ) { - switch ( c ) { - case 't': - tag_text = optarg; - break; - case 'p': - priority_text = optarg; - break; - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - vcreate_syntax ( argv ); - return 1; - } - } - if ( optind != ( argc - 1 ) ) { - vcreate_syntax ( argv ); - return 1; - } - trunk_name = argv[optind]; - if ( ! tag_text ) { - vcreate_syntax ( argv ); - return 1; - } + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &vcreate_cmd, &opts ) ) != 0 ) + return rc; - /* Identify network device */ - trunk = find_netdev ( trunk_name ); - if ( ! trunk ) { - printf ( "%s: no such interface\n", trunk_name ); - return 1; - } - tag = strtoul ( tag_text, &endp, 10 ); - if ( *endp ) { - printf ( "%s: invalid tag\n", tag_text ); - return 1; - } - if ( priority_text ) { - priority = strtoul ( priority_text, &endp, 10 ); - if ( *endp ) { - printf ( "%s: invalid priority\n", priority_text ); - return 1; - } - } else { - priority = 0; - } + /* Parse trunk interface */ + if ( ( rc = parse_netdev ( argv[optind], &trunk ) ) != 0 ) + return rc; /* Create VLAN device */ - if ( ( rc = vlan_create ( trunk, tag, priority ) ) != 0 ) { + if ( ( rc = vlan_create ( trunk, opts.tag, opts.priority ) ) != 0 ) { printf ( "Could not create VLAN device: %s\n", strerror ( rc ) ); - return 1; + return rc; } return 0; } -static void vdestroy_syntax ( char **argv ) { - printf ( "Usage:\n %s \n", argv[0] ); -} +/** "vdestroy" options */ +struct vdestroy_options {}; +/** "vdestroy" option list */ +static struct option_descriptor vdestroy_opts[] = {}; + +/** "vdestroy" command descriptor */ +static struct command_descriptor vdestroy_cmd = + COMMAND_DESC ( struct vdestroy_options, vdestroy_opts, 1, 1, + "", + "Destroy a VLAN interface" ); + +/** + * "vdestroy" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int vdestroy_exec ( int argc, char **argv ) { - static struct option vdestroy_opts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - const char *netdev_name; + struct vdestroy_options opts; struct net_device *netdev; - int c; int rc; - /* Parse command line */ - while ( ( c = getopt_long ( argc, argv, "h", vdestroy_opts, - NULL ) ) >= 0 ) { - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - vdestroy_syntax ( argv ); - return 1; - } - } - if ( optind != ( argc - 1 ) ) { - vdestroy_syntax ( argv ); - return 1; - } - netdev_name = argv[optind]; + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &vdestroy_cmd, &opts ) ) != 0 ) + return rc; - /* Identify network device */ - netdev = find_netdev ( netdev_name ); - if ( ! netdev ) { - printf ( "%s: no such interface\n", netdev_name ); - return 1; - } + /* Parse trunk interface */ + if ( ( rc = parse_netdev ( argv[optind], &netdev ) ) != 0 ) + return rc; /* Destroy VLAN device */ if ( ( rc = vlan_destroy ( netdev ) ) != 0 ) { printf ( "Could not destroy VLAN device: %s\n", strerror ( rc ) ); - return 1; + return rc; } return 0; } +/** VLAN commands */ struct command vlan_commands[] __command = { { .name = "vcreate", From 17b337d4a8ae0a355a8e61e967f5015907590e9e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 16:39:36 +0000 Subject: [PATCH 20/85] [autoboot] Use generic option-parsing library Total saving: 32 bytes. Signed-off-by: Michael Brown --- src/hci/commands/autoboot_cmd.c | 115 ++++++++++++++++++++++++-------- src/include/usr/autoboot.h | 2 +- src/usr/autoboot.c | 8 ++- 3 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/hci/commands/autoboot_cmd.c b/src/hci/commands/autoboot_cmd.c index 17bd6bcf..33788682 100644 --- a/src/hci/commands/autoboot_cmd.c +++ b/src/hci/commands/autoboot_cmd.c @@ -1,53 +1,110 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + #include +#include #include +#include #include #include FILE_LICENCE ( GPL2_OR_LATER ); +/** @file + * + * Booting commands + * + */ + +/** "autoboot" options */ +struct autoboot_options {}; + +/** "autoboot" option list */ +static struct option_descriptor autoboot_opts[] = {}; + +/** "autoboot" command descriptor */ +static struct command_descriptor autoboot_cmd = + COMMAND_DESC ( struct autoboot_options, autoboot_opts, 0, 0, + "", + "Attempt to boot the system" ); + +/** + * "autoboot" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int autoboot_exec ( int argc, char **argv ) { + struct autoboot_options opts; + int rc; - if ( argc != 1 ) { - printf ( "Usage:\n" - " %s\n" - "\n" - "Attempts to boot the system\n", - argv[0] ); - return 1; - } + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &autoboot_cmd, &opts ) ) != 0 ) + return rc; - autoboot(); + /* Try to boot */ + if ( ( rc = autoboot() ) != 0 ) + return rc; - /* Can never return success by definition */ - return 1; + return 0; } +/** "netboot" options */ +struct netboot_options {}; + +/** "netboot" option list */ +static struct option_descriptor netboot_opts[] = {}; + +/** "netboot" command descriptor */ +static struct command_descriptor netboot_cmd = + COMMAND_DESC ( struct netboot_options, netboot_opts, 1, 1, + "", + "Attempt to boot the system from " ); + +/** + * "netboot" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int netboot_exec ( int argc, char **argv ) { - const char *netdev_name; + struct netboot_options opts; struct net_device *netdev; + int rc; - if ( argc != 2 ) { - printf ( "Usage:\n" - " %s \n" - "\n" - "Attempts to boot the system from \n", - argv[0] ); - return 1; - } - netdev_name = argv[1]; + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &netboot_cmd, &opts ) ) != 0 ) + return rc; - netdev = find_netdev ( netdev_name ); - if ( ! netdev ) { - printf ( "%s: no such interface\n", netdev_name ); - return 1; - } + /* Parse interface */ + if ( ( rc = parse_netdev ( argv[optind], &netdev ) ) != 0 ) + return rc; - netboot ( netdev ); + /* Try to boot */ + if ( ( rc = netboot ( netdev ) ) != 0 ) + return rc; - /* Can never return success by definition */ - return 1; + return 0; } +/** Booting commands */ struct command autoboot_commands[] __command = { { .name = "autoboot", diff --git a/src/include/usr/autoboot.h b/src/include/usr/autoboot.h index 46e3b481..e9abf833 100644 --- a/src/include/usr/autoboot.h +++ b/src/include/usr/autoboot.h @@ -15,7 +15,7 @@ struct net_device; extern int shutdown_exit_flags; extern int netboot ( struct net_device *netdev ); -extern void autoboot ( void ); +extern int autoboot ( void ); extern int boot_next_server_and_filename ( struct in_addr next_server, const char *filename ); extern int boot_root_path ( const char *root_path ); diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index d87e3627..c7492ea7 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -293,22 +293,24 @@ static void close_all_netdevs ( void ) { /** * Boot the system */ -void autoboot ( void ) { +int autoboot ( void ) { struct net_device *boot_netdev; struct net_device *netdev; + int rc = -ENODEV; /* If we have an identifable boot device, try that first */ close_all_netdevs(); if ( ( boot_netdev = find_boot_netdev() ) ) - netboot ( boot_netdev ); + rc = netboot ( boot_netdev ); /* If that fails, try booting from any of the other devices */ for_each_netdev ( netdev ) { if ( netdev == boot_netdev ) continue; close_all_netdevs(); - netboot ( netdev ); + rc = netboot ( netdev ); } printf ( "No more network devices\n" ); + return rc; } From 9e9c9adf1058c77cc7df5651221dd74de3a3282c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 16:57:58 +0000 Subject: [PATCH 21/85] [settings] Use generic option-parsing library Total cost: 75 bytes. Signed-off-by: Michael Brown --- src/hci/commands/config_cmd.c | 103 +++++++++++++++++++----- src/hci/commands/nvo_cmd.c | 146 ++++++++++++++++++++++++++++------ src/include/ipxe/errfile.h | 1 + 3 files changed, 206 insertions(+), 44 deletions(-) diff --git a/src/hci/commands/config_cmd.c b/src/hci/commands/config_cmd.c index 53b10f91..84c2e32a 100644 --- a/src/hci/commands/config_cmd.c +++ b/src/hci/commands/config_cmd.c @@ -1,38 +1,103 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + #include #include +#include +#include #include +#include #include #include FILE_LICENCE ( GPL2_OR_LATER ); -static int config_exec ( int argc, char **argv ) { - char *settings_name; - struct settings *settings; - int rc; +/** @file + * + * Configuration UI commands + * + */ - if ( argc > 2 ) { - printf ( "Usage: %s [scope]\n" - "Opens the option configuration console\n", argv[0] ); - return 1; - } +/** "config" options */ +struct config_options {}; - settings_name = ( ( argc == 2 ) ? argv[1] : "" ); - settings = find_settings ( settings_name ); - if ( ! settings ) { - printf ( "No such scope \"%s\"\n", settings_name ); - return 1; - } +/** "config" option list */ +static struct option_descriptor config_opts[] = {}; - if ( ( rc = settings_ui ( settings ) ) != 0 ) { - printf ( "Could not save settings: %s\n", - strerror ( rc ) ); - return 1; +/** "config" command descriptor */ +static struct command_descriptor config_cmd = + COMMAND_DESC ( struct config_options, config_opts, 0, 1, + "[]", + "Open the option configuration console" ); + +/** + * Parse settings scope name + * + * @v text Text + * @ret value Integer value + * @ret rc Return status code + */ +static int parse_settings ( const char *text, struct settings **value ) { + + /* Sanity check */ + assert ( text != NULL ); + + /* Parse scope name */ + *value = find_settings ( text ); + if ( ! *value ) { + printf ( "\"%s\": no such scope\n", text ); + return -EINVAL; } return 0; } +/** + * "config" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int config_exec ( int argc, char **argv ) { + struct config_options opts; + struct settings *settings; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &config_cmd, &opts ) ) != 0 ) + return rc; + + /* Parse settings option, if present */ + if ( ( rc = parse_settings ( ( ( optind < argc ) ? argv[optind] : "" ), + &settings ) ) != 0 ) + return rc; + + /* Run settings UI */ + if ( ( rc = settings_ui ( settings ) ) != 0 ) { + printf ( "Could not save settings: %s\n", strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** Configuration UI commands */ struct command config_command __command = { .name = "config", .exec = config_exec, diff --git a/src/hci/commands/nvo_cmd.c b/src/hci/commands/nvo_cmd.c index cebb8949..87bdd8a1 100644 --- a/src/hci/commands/nvo_cmd.c +++ b/src/hci/commands/nvo_cmd.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + #include #include #include @@ -6,42 +24,96 @@ #include #include #include +#include FILE_LICENCE ( GPL2_OR_LATER ); +/** @file + * + * Non-volatile option commands + * + */ + +/** "show" options */ +struct show_options {}; + +/** "show" option list */ +static struct option_descriptor show_opts[] = {}; + +/** "show" command descriptor */ +static struct command_descriptor show_cmd = + COMMAND_DESC ( struct show_options, show_opts, 1, 1, + "", "" ); + +/** + * "show" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int show_exec ( int argc, char **argv ) { + struct show_options opts; + const char *name; char buf[256]; int rc; - if ( argc != 2 ) { - printf ( "Syntax: %s \n", argv[0] ); - return 1; - } + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &show_cmd, &opts ) ) != 0 ) + return rc; - if ( ( rc = fetchf_named_setting ( argv[1], buf, - sizeof ( buf ) ) ) < 0 ){ + /* Parse setting name */ + name = argv[optind]; + + /* Fetch setting */ + if ( ( rc = fetchf_named_setting ( name, buf, + sizeof ( buf ) ) ) < 0 ) { printf ( "Could not find \"%s\": %s\n", - argv[1], strerror ( rc ) ); - return 1; + name, strerror ( rc ) ); + return rc; } - printf ( "%s = %s\n", argv[1], buf ); + /* Print setting value */ + printf ( "%s = %s\n", name, buf ); + return 0; } +/** "set" options */ +struct set_options {}; + +/** "set" option list */ +static struct option_descriptor set_opts[] = {}; + +/** "set" command descriptor */ +static struct command_descriptor set_cmd = + COMMAND_DESC ( struct set_options, set_opts, 2, MAX_ARGUMENTS, + " ", "" ); + +/** + * "set" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int set_exec ( int argc, char **argv ) { + struct set_options opts; + const char *name; size_t len; int i; int rc; - if ( argc < 3 ) { - printf ( "Syntax: %s \n", argv[0] ); - return 1; - } + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &set_cmd, &opts ) ) != 0 ) + return rc; + + /* Parse setting name */ + name = argv[optind]; /* Determine total length of command line */ len = 1; /* NUL */ - for ( i = 2 ; i < argc ; i++ ) + for ( i = optind + 1 ; i < argc ; i++ ) len += ( 1 /* possible space */ + strlen ( argv[i] ) ); { @@ -50,39 +122,63 @@ static int set_exec ( int argc, char **argv ) { /* Assemble command line */ buf[0] = '\0'; - for ( i = 2 ; i < argc ; i++ ) { + for ( i = optind + 1 ; i < argc ; i++ ) { ptr += sprintf ( ptr, "%s%s", ( buf[0] ? " " : "" ), argv[i] ); } assert ( ptr < ( buf + len ) ); - if ( ( rc = storef_named_setting ( argv[1], buf ) ) != 0 ) { + if ( ( rc = storef_named_setting ( name, buf ) ) != 0 ) { printf ( "Could not set \"%s\"=\"%s\": %s\n", - argv[1], buf, strerror ( rc ) ); - return 1; + name, buf, strerror ( rc ) ); + return rc; } } return 0; } +/** "clear" options */ +struct clear_options {}; + +/** "clear" option list */ +static struct option_descriptor clear_opts[] = {}; + +/** "clear" command descriptor */ +static struct command_descriptor clear_cmd = + COMMAND_DESC ( struct clear_options, clear_opts, 1, 1, + "", "" ); + +/** + * "clear" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int clear_exec ( int argc, char **argv ) { + struct clear_options opts; + const char *name; int rc; - if ( argc != 2 ) { - printf ( "Syntax: %s \n", argv[0] ); - return 1; - } + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &clear_cmd, &opts ) ) != 0 ) + return rc; - if ( ( rc = delete_named_setting ( argv[1] ) ) != 0 ) { + /* Parse setting name */ + name = argv[optind]; + + /* Clear setting */ + if ( ( rc = delete_named_setting ( name ) ) != 0 ) { printf ( "Could not clear \"%s\": %s\n", - argv[1], strerror ( rc ) ); - return 1; + name, strerror ( rc ) ); + return rc; } return 0; } +/** Non-volatile option commands */ struct command nvo_commands[] __command = { { .name = "show", diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7b415928..5b989ed2 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -228,6 +228,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_iwmgmt ( ERRFILE_OTHER | 0x00190000 ) #define ERRFILE_linux_smbios ( ERRFILE_OTHER | 0x001a0000 ) #define ERRFILE_lotest ( ERRFILE_OTHER | 0x001b0000 ) +#define ERRFILE_config_cmd ( ERRFILE_OTHER | 0x001c0000 ) /** @} */ From 398a6e9a50c1b2afedaa104c38b8a4a18447d430 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 22:14:28 +0000 Subject: [PATCH 22/85] [ifmgmt] Use generic option-parsing library Total cost: 66 bytes Signed-off-by: Michael Brown --- src/arch/i386/hci/commands/pxe_cmd.c | 75 ++++++++++- src/hci/commands/ifmgmt_cmd.c | 180 ++++++++++++++------------- src/hci/commands/iwmgmt_cmd.c | 51 +++++++- src/include/hci/ifmgmt_cmd.h | 9 +- src/include/ipxe/errfile.h | 1 + 5 files changed, 219 insertions(+), 97 deletions(-) diff --git a/src/arch/i386/hci/commands/pxe_cmd.c b/src/arch/i386/hci/commands/pxe_cmd.c index 6b4fa8fa..8d572117 100644 --- a/src/arch/i386/hci/commands/pxe_cmd.c +++ b/src/arch/i386/hci/commands/pxe_cmd.c @@ -1,26 +1,97 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + #include #include +#include #include #include FILE_LICENCE ( GPL2_OR_LATER ); +/** @file + * + * PXE commands + * + */ + +/** "startpxe" command descriptor */ +static struct command_descriptor startpxe_cmd = + COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, + "[]", "" ); + +/** + * "startpxe" payload + * + * @v netdev Network device + * @ret rc Return status code + */ static int startpxe_payload ( struct net_device *netdev ) { + if ( netdev_is_open ( netdev ) ) pxe_activate ( netdev ); + return 0; } +/** + * The "startpxe" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int startpxe_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, startpxe_payload, - "Activate PXE on" ); + return ifcommon_exec ( argc, argv, &startpxe_cmd, startpxe_payload, 0 ); } +/** "stoppxe" options */ +struct stoppxe_options {}; + +/** "stoppxe" option list */ +static struct option_descriptor stoppxe_opts[] = {}; + +/** "stoppxe" command descriptor */ +static struct command_descriptor stoppxe_cmd = + COMMAND_DESC ( struct stoppxe_options, stoppxe_opts, 0, 0, + "", "" ); + +/** + * The "stoppxe" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int stoppxe_exec ( int argc __unused, char **argv __unused ) { + struct stoppxe_options opts; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &stoppxe_cmd, &opts ) ) != 0 ) + return rc; + pxe_deactivate(); + return 0; } +/** PXE commands */ struct command pxe_commands[] __command = { { .name = "startpxe", diff --git a/src/hci/commands/ifmgmt_cmd.c b/src/hci/commands/ifmgmt_cmd.c index ae80cde4..9724f790 100644 --- a/src/hci/commands/ifmgmt_cmd.c +++ b/src/hci/commands/ifmgmt_cmd.c @@ -19,9 +19,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include #include #include +#include #include #include @@ -31,136 +33,138 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** Options shared by all if commands */ -static struct option ifcommon_longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, -}; - -/** - * Print syntax of if command - * - * @v argv Command arguments - * @v verb Verb describing the action of the command - */ -static void ifcommon_syntax ( char **argv, const char *verb ) { - printf ( "Usage:\n" - " %s [] [...]\n" - "\n" - "%s the specified network interfaces\n", - argv[0], verb ); -} - -/** - * Execute if command over all network devices - * - * @v payload Command to execute - * @ret rc Exit code - */ -static int ifcommon_do_all ( int ( * payload ) ( struct net_device * ) ) { - struct net_device *netdev; - int rc = 0; - - /* Execute payload for each network device */ - for_each_netdev ( netdev ) { - if ( payload ( netdev ) != 0 ) - rc = 1; - } - return rc; -} - -/** - * Execute if command over list of network devices - * - * @v payload Command to execute - * @ret rc Exit code - */ -static int ifcommon_do_list ( int ( * payload ) ( struct net_device * ), - char **list, unsigned int count ) { - const char *netdev_name; - struct net_device *netdev; - int rc = 0; - - while ( count-- ) { - netdev_name = *(list++); - netdev = find_netdev ( netdev_name ); - if ( ! netdev ) { - printf ( "%s: no such interface\n", netdev_name ); - rc = 1; - continue; - } - if ( payload ( netdev ) != 0 ) - rc = 1; - } - return rc; -} +/** "if" command options */ +struct option_descriptor ifcommon_opts[0]; /** * Execute if command * * @v argc Argument count * @v argv Argument list + * @v cmd Command descriptor * @v payload Command to execute * @v verb Verb describing the action of the command - * @ret rc Exit code + * @ret rc Return status code */ int ifcommon_exec ( int argc, char **argv, + struct command_descriptor *cmd, int ( * payload ) ( struct net_device * ), - const char *verb ) { - int c; + int stop_on_first_success ) { + struct ifcommon_options opts; + struct net_device *netdev; + int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", ifcommon_longopts, - NULL ) ) >= 0 ) { - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - ifcommon_syntax ( argv, verb ); - return 1; + if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 ) + return rc; + + if ( optind != argc ) { + /* Treat arguments as a list of interfaces to try */ + while ( optind != argc ) { + if ( ( rc = parse_netdev ( argv[optind++], + &netdev ) ) != 0 ) { + continue; + } + if ( ( ( rc = payload ( netdev ) ) == 0 ) && + stop_on_first_success ) { + return 0; + } + } + } else { + /* Try all interfaces */ + rc = -ENODEV; + for_each_netdev ( netdev ) { + if ( ( ( rc = payload ( netdev ) ) == 0 ) && + stop_on_first_success ) { + return 0; + } } } - if ( optind == argc ) { - return ifcommon_do_all ( payload ); - } else { - return ifcommon_do_list ( payload, &argv[optind], - ( argc - optind ) ); - } + return rc; } -/* "ifopen" command */ +/** "ifopen" command descriptor */ +static struct command_descriptor ifopen_cmd = + COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, + "[...]", + "Open network interface(s)" ); +/** + * "ifopen" payload + * + * @v netdev Network device + * @ret rc Return status code + */ static int ifopen_payload ( struct net_device *netdev ) { return ifopen ( netdev ); } +/** + * The "ifopen" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int ifopen_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, ifopen_payload, "Open" ); + return ifcommon_exec ( argc, argv, &ifopen_cmd, ifopen_payload, 0 ); } -/* "ifclose" command */ +/** "ifclose" command descriptor */ +static struct command_descriptor ifclose_cmd = + COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, + "[...]", + "Close network interface(s)" ); +/** + * "ifclose" payload + * + * @v netdev Network device + * @ret rc Return status code + */ static int ifclose_payload ( struct net_device *netdev ) { ifclose ( netdev ); return 0; } +/** + * The "ifclose" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int ifclose_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, ifclose_payload, "Close" ); + return ifcommon_exec ( argc, argv, &ifclose_cmd, ifclose_payload, 0 ); } -/* "ifstat" command */ +/** "ifstat" command descriptor */ +static struct command_descriptor ifstat_cmd = + COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, + "[...]", + "Show network interface(s)" ); +/** + * "ifstat" payload + * + * @v netdev Network device + * @ret rc Return status code + */ static int ifstat_payload ( struct net_device *netdev ) { ifstat ( netdev ); return 0; } +/** + * The "ifstat" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int ifstat_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, - ifstat_payload, "Display status of" ); + return ifcommon_exec ( argc, argv, &ifstat_cmd, ifstat_payload, 0 ); } /** Interface management commands */ diff --git a/src/hci/commands/iwmgmt_cmd.c b/src/hci/commands/iwmgmt_cmd.c index 8c00a206..3922141b 100644 --- a/src/hci/commands/iwmgmt_cmd.c +++ b/src/hci/commands/iwmgmt_cmd.c @@ -21,11 +21,28 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include -/* "iwstat" command */ +/** @file + * + * Wireless interface management commands + * + */ +/** "iwstat" command descriptor */ +static struct command_descriptor iwstat_cmd = + COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, + "[...]", + "Show wireless interface(s)" ); + +/** + * "iwstat" payload + * + * @v netdev Network device + * @ret rc Return status code + */ static int iwstat_payload ( struct net_device *netdev ) { struct net80211_device *dev = net80211_get ( netdev ); @@ -35,13 +52,29 @@ static int iwstat_payload ( struct net_device *netdev ) { return 0; } +/** + * The "iwstat" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int iwstat_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, - iwstat_payload, "Display wireless status of" ); + return ifcommon_exec ( argc, argv, &iwstat_cmd, iwstat_payload, 0 ); } -/* "iwlist" command */ +/** "iwlist" command descriptor */ +static struct command_descriptor iwlist_cmd = + COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, + "[...]", + "List wireless networks" ); +/** + * "iwlist" payload + * + * @v netdev Network device + * @ret rc Return status code + */ static int iwlist_payload ( struct net_device *netdev ) { struct net80211_device *dev = net80211_get ( netdev ); @@ -51,9 +84,15 @@ static int iwlist_payload ( struct net_device *netdev ) { return 0; } +/** + * The "iwlist" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int iwlist_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, iwlist_payload, - "List wireless networks available via" ); + return ifcommon_exec ( argc, argv, &iwlist_cmd, iwlist_payload, 0 ); } /** Wireless interface management commands */ diff --git a/src/include/hci/ifmgmt_cmd.h b/src/include/hci/ifmgmt_cmd.h index e9c810ab..a7751cb2 100644 --- a/src/include/hci/ifmgmt_cmd.h +++ b/src/include/hci/ifmgmt_cmd.h @@ -21,10 +21,17 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include + struct net_device; +struct ifcommon_options {}; + +extern struct option_descriptor ifcommon_opts[0]; + extern int ifcommon_exec ( int argc, char **argv, + struct command_descriptor *cmd, int ( * payload ) ( struct net_device * ), - const char *verb ); + int stop_on_first_success ); #endif /* _IFMGMT_CMD_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 5b989ed2..e475eca5 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -229,6 +229,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_linux_smbios ( ERRFILE_OTHER | 0x001a0000 ) #define ERRFILE_lotest ( ERRFILE_OTHER | 0x001b0000 ) #define ERRFILE_config_cmd ( ERRFILE_OTHER | 0x001c0000 ) +#define ERRFILE_ifmgmt_cmd ( ERRFILE_OTHER | 0x001d0000 ) /** @} */ From 07c6b79102d4ec462567560de658275672c539de Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 18:18:01 +0000 Subject: [PATCH 23/85] [dhcp] Use generic option-parsing library Total saving: 329 bytes. Signed-off-by: Michael Brown --- src/hci/commands/dhcp_cmd.c | 155 ++++++++---------------------------- 1 file changed, 35 insertions(+), 120 deletions(-) diff --git a/src/hci/commands/dhcp_cmd.c b/src/hci/commands/dhcp_cmd.c index 6da0d637..fba89772 100644 --- a/src/hci/commands/dhcp_cmd.c +++ b/src/hci/commands/dhcp_cmd.c @@ -30,7 +30,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include +#include /** @file * @@ -38,26 +40,19 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** - * "dhcp" command syntax message - * - * @v argv Argument list - */ -static void dhcp_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s [] [...]\n" - "\n" - "Configure a network interface using DHCP\n", - argv[0] ); -} +/** "dhcp" command descriptor */ +static struct command_descriptor dhcp_cmd = + COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, + "[] [...]", + "Configure network interface(s) using DHCP" ); /** * Execute "dhcp" command for a network device * * @v netdev Network device - * @ret rc Exit code + * @ret rc Return status code */ -static int dhcp_exec_netdev ( struct net_device *netdev ) { +static int dhcp_payload ( struct net_device *netdev ) { int rc; if ( ( rc = dhcp ( netdev ) ) != 0 ) { @@ -67,145 +62,65 @@ static int dhcp_exec_netdev ( struct net_device *netdev ) { /* Close device on failure, to avoid memory exhaustion */ netdev_close ( netdev ); - return 1; + return rc; } return 0; } -/** - * Execute "dhcp" command for a named network device - * - * @v netdev_name Network device name - * @ret rc Exit code - */ -static int dhcp_exec_name ( const char *netdev_name ) { - struct net_device *netdev; - - netdev = find_netdev ( netdev_name ); - if ( ! netdev ) { - printf ( "No such interface \"%s\"\n", netdev_name ); - return 1; - } - - return dhcp_exec_netdev ( netdev ); -} - /** * The "dhcp" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int dhcp_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - const char *netdev_name; - struct net_device *netdev; - int c; - int rc; - - /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - dhcp_syntax ( argv ); - return 1; - } - } - - if ( optind != argc ) { - /* Treat arguments as a list of interfaces to try */ - while ( optind != argc ) { - netdev_name = argv[optind++]; - if ( ( rc = dhcp_exec_name ( netdev_name ) ) == 0 ) - return 0; - } - } else { - /* Try all interfaces */ - for_each_netdev ( netdev ) { - if ( ( rc = dhcp_exec_netdev ( netdev ) ) == 0 ) - return 0; - } - } - - return 1; + return ifcommon_exec ( argc, argv, &dhcp_cmd, dhcp_payload, 1 ); } -/** - * "pxebs" command syntax message - * - * @v argv Argument list - */ -static void pxebs_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s \n" - "\n" - "Perform PXE Boot Server discovery\n", - argv[0] ); -} +/** "pxebs" options */ +struct pxebs_options {}; + +/** "pxebs" option list */ +static struct option_descriptor pxebs_opts[] = {}; + +/** "pxebs" command descriptor */ +static struct command_descriptor pxebs_cmd = + COMMAND_DESC ( struct pxebs_options, pxebs_opts, 2, 2, + " ", + "Perform PXE Boot Server discovery" ); /** * The "pxebs" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int pxebs_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - const char *netdev_txt; - const char *pxe_type_txt; + struct pxebs_options opts; struct net_device *netdev; unsigned int pxe_type; - char *end; - int c; int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - pxebs_syntax ( argv ); - return 1; - } - } - if ( optind != ( argc - 2 ) ) { - pxebs_syntax ( argv ); - return 1; - } - netdev_txt = argv[optind]; - pxe_type_txt = argv[ optind + 1 ]; + if ( ( rc = parse_options ( argc, argv, &pxebs_cmd, &opts ) ) != 0 ) + return rc; - /* Parse arguments */ - netdev = find_netdev ( netdev_txt ); - if ( ! netdev ) { - printf ( "No such interface: %s\n", netdev_txt ); - return 1; - } - pxe_type = strtoul ( pxe_type_txt, &end, 0 ); - if ( *end ) { - printf ( "Bad server type: %s\n", pxe_type_txt ); - return 1; - } + /* Parse net device name */ + if ( ( rc = parse_netdev ( argv[optind], &netdev ) ) != 0 ) + return rc; + + /* Parse boot server type */ + if ( ( rc = parse_integer ( argv[ optind + 1 ], &pxe_type ) ) != 0 ) + return rc; /* Perform Boot Server Discovery */ if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) { printf ( "Could not discover boot server on %s: %s\n", netdev->name, strerror ( rc ) ); - return 1; + return rc; } return 0; From ee53e69bab842a0d6d34d50a85715356008c8581 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 18:37:54 +0000 Subject: [PATCH 24/85] [digest] Use generic option-parsing library Total saving: 68 bytes. Signed-off-by: Michael Brown --- src/hci/commands/digest_cmd.c | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/hci/commands/digest_cmd.c b/src/hci/commands/digest_cmd.c index e28e6c3b..99c196a1 100644 --- a/src/hci/commands/digest_cmd.c +++ b/src/hci/commands/digest_cmd.c @@ -19,25 +19,31 @@ #include #include #include +#include #include +#include #include #include - #include #include -/** - * "digest" command syntax message +/** @file + * + * Digest commands * - * @v argv Argument list */ -static void digest_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s \n" - "\n" - "Calculate the %s of an image\n", - argv[0], argv[0] ); -} + +/** "digest" options */ +struct digest_options {}; + +/** "digest" option list */ +static struct option_descriptor digest_opts[] = {}; + +/** "digest" command descriptor */ +static struct command_descriptor digest_cmd = + COMMAND_DESC ( struct digest_options, digest_opts, 1, MAX_ARGUMENTS, + " [...]", + "Calculate the digest of an image" ); /** * The "digest" command @@ -45,11 +51,11 @@ static void digest_syntax ( char **argv ) { * @v argc Argument count * @v argv Argument list * @v digest Digest algorithm - * @ret rc Exit code + * @ret rc Return status code */ static int digest_exec ( int argc, char **argv, struct digest_algorithm *digest ) { - const char *image_name; + struct digest_options opts; struct image *image; uint8_t digest_ctx[digest->ctxsize]; uint8_t digest_out[digest->digestsize]; @@ -59,23 +65,17 @@ static int digest_exec ( int argc, char **argv, size_t frag_len; int i; unsigned j; + int rc; - if ( argc < 2 || - !strcmp ( argv[1], "--help" ) || - !strcmp ( argv[1], "-h" ) ) { - digest_syntax ( argv ); - return 1; - } + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &digest_cmd, &opts ) ) != 0 ) + return rc; - for ( i = 1 ; i < argc ; i++ ) { - image_name = argv[i]; + for ( i = optind ; i < argc ; i++ ) { /* find image */ - image = find_image ( image_name ); - if ( ! image ) { - printf ( "No such image: %s\n", image_name ); + if ( ( rc = parse_image ( argv[i], &image ) ) != 0 ) continue; - } offset = 0; len = image->len; From 59980a6176fe71877917ee59e363514dfa67f66d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 19:06:06 +0000 Subject: [PATCH 25/85] [fc] Use generic option-parsing library Total saving: 111 bytes. Signed-off-by: Michael Brown --- src/hci/commands/fcmgmt_cmd.c | 243 +++++++++++++++++++--------------- src/include/ipxe/errfile.h | 1 + 2 files changed, 137 insertions(+), 107 deletions(-) diff --git a/src/hci/commands/fcmgmt_cmd.c b/src/hci/commands/fcmgmt_cmd.c index 98647c13..c76554f6 100644 --- a/src/hci/commands/fcmgmt_cmd.c +++ b/src/hci/commands/fcmgmt_cmd.c @@ -19,11 +19,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include #include #include #include #include +#include #include #include @@ -33,36 +35,96 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -static void fcstat_syntax ( char **argv ) { - printf ( "Usage:\n %s\n", argv[0] ); +/** + * Parse Fibre Channel port name + * + * @v text Text + * @ret port Fibre Channel port + * @ret rc Return status code + */ +static int parse_fc_port ( const char *text, struct fc_port **port ) { + + /* Sanity check */ + assert ( text != NULL ); + + /* Find Fibre Channel port */ + *port = fc_port_find ( text ); + if ( ! *port ) { + printf ( "\"%s\": no such port\n", text ); + return -ENODEV; + } + + return 0; } +/** + * Parse Fibre Channel port ID + * + * @v text Text + * @ret port_id Fibre Channel port ID + * @ret rc Return status code + */ +static int parse_fc_port_id ( const char *text, struct fc_port_id *port_id ) { + int rc; + + /* Sanity check */ + assert ( text != NULL ); + + /* Parse port ID */ + if ( ( rc = fc_id_aton ( text, port_id ) ) != 0 ) { + printf ( "\"%s\": invalid port ID\n", text ); + return -EINVAL; + } + + return 0; +} + +/** + * Parse Fibre Channel ELS handler name + * + * @v text Text + * @ret handler Fibre Channel ELS handler + * @ret rc Return status code + */ +static int parse_fc_els_handler ( const char *text, + struct fc_els_handler **handler ) { + + for_each_table_entry ( (*handler), FC_ELS_HANDLERS ) { + if ( strcasecmp ( (*handler)->name, text ) == 0 ) + return 0; + } + + printf ( "\"%s\": unrecognised ELS\n", text ); + return -ENOENT; +} + +/** "fcstat" options */ +struct fcstat_options {}; + +/** "fcstat" option list */ +static struct option_descriptor fcstat_opts[] = {}; + +/** "fcstat" command descriptor */ +static struct command_descriptor fcstat_cmd = + COMMAND_DESC ( struct fcstat_options, fcstat_opts, 0, 0, + "", "" ); + +/** + * The "fcstat" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int fcstat_exec ( int argc, char **argv ) { - static struct option fcstat_opts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; + struct fcstat_options opts; struct fc_port *port; struct fc_peer *peer; - int c; + int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", fcstat_opts, - NULL ) ) >= 0 ) { - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - fcstat_syntax ( argv ); - return 1; - } - } - - if ( optind != argc ) { - fcstat_syntax ( argv ); - return 1; - } + if ( ( rc = parse_options ( argc, argv, &fcstat_cmd, &opts ) ) != 0 ) + return rc; list_for_each_entry ( port, &fc_ports, list ) fcportstat ( port ); @@ -72,105 +134,72 @@ static int fcstat_exec ( int argc, char **argv ) { return 0; } -static void fcels_syntax ( char **argv ) { - printf ( "Usage:\n %s [--port ] [--id ]" - " \n", argv[0] ); -} - -static struct fc_els_handler * fcels_find_handler ( const char *name ) { - struct fc_els_handler *handler; - - for_each_table_entry ( handler, FC_ELS_HANDLERS ) { - if ( strcasecmp ( handler->name, name ) == 0 ) - return handler; - } - return NULL; -} - -static int fcels_exec ( int argc, char **argv ) { - static struct option fcels_opts[] = { - { "help", 0, NULL, 'h' }, - { "port", required_argument, NULL, 'p' }, - { "id", required_argument, NULL, 'i' }, - { NULL, 0, NULL, 0 }, - }; - const char *handler_text; - const char *port_text = NULL; - const char *id_text = NULL; - struct fc_els_handler *handler; +/** "fcels" options */ +struct fcels_options { + /** Fibre Channel port */ struct fc_port *port; - struct fc_port_id id_buf; + /** Fibre Channel peer port ID */ + struct fc_port_id peer_port_id; +}; + +/** "fcels" option list */ +static struct option_descriptor fcels_opts[] = { + OPTION_DESC ( "port", 'p', required_argument, + struct fcels_options, port, parse_fc_port ), + OPTION_DESC ( "id", 'i', required_argument, + struct fcels_options, peer_port_id, parse_fc_port_id ), +}; + +/** "fcels" command descriptor */ +static struct command_descriptor fcels_cmd = + COMMAND_DESC ( struct fcels_options, fcels_opts, 1, 1, + "[--port ] [--id ] ", "" ); + +/** + * The "fcels" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int fcels_exec ( int argc, char **argv ) { + struct fcels_options opts; + struct fc_els_handler *handler; struct fc_port_id *id; - int c; + int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "hp:i:", fcels_opts, - NULL ) ) >= 0 ) { - switch ( c ) { - case 'p': - port_text = optarg; - break; - case 'i': - id_text = optarg; - break; - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - fcels_syntax ( argv ); - return 1; - } - } + if ( ( rc = parse_options ( argc, argv, &fcels_cmd, &opts ) ) != 0 ) + return rc; - /* Identify ELS */ - if ( optind != ( argc - 1 ) ) { - fcels_syntax ( argv ); - return 1; - } - handler_text = argv[optind]; - handler = fcels_find_handler ( handler_text ); - if ( ! handler ) { - printf ( "%s: unrecognised ELS\n", handler_text ); - return 1; - } + /* Parse ELS handler */ + if ( ( rc = parse_fc_els_handler ( argv[optind], &handler ) ) != 0 ) + return rc; - /* Identify port */ - if ( port_text ) { - /* Use specified port */ - port = fc_port_find ( port_text ); - if ( ! port ) { - printf ( "%s: no such port\n", port_text ); - return 1; - } - } else { - /* Use first port */ - port = list_first_entry ( &fc_ports, struct fc_port, list ); - if ( ! port ) { + /* Use first port if no port specified */ + if ( ! opts.port ) { + opts.port = list_first_entry ( &fc_ports, struct fc_port, + list ); + if ( ! opts.port ) { printf ( "No ports\n" ); - return 1; + return -ENODEV; } } - assert ( port != NULL ); - /* Identify port ID */ - if ( id_text ) { - if ( fc_id_aton ( id_text, &id_buf ) != 0 ) { - printf ( "%s: invalid port ID\n", id_text ); - return 1; - } - id = &id_buf; - } else { - if ( fc_link_ok ( &port->link ) && - ! ( port->flags & FC_PORT_HAS_FABRIC ) ) { - id = &port->ptp_link_port_id; + /* Use link peer port ID if no peer port ID specified */ + id = &opts.peer_port_id; + if ( memcmp ( id, &fc_empty_port_id, sizeof ( *id ) ) == 0 ) { + if ( fc_link_ok ( &opts.port->link ) && + ! ( opts.port->flags & FC_PORT_HAS_FABRIC ) ) { + id = &opts.port->ptp_link_port_id; } else { id = &fc_f_port_id; } } - assert ( id != NULL ); - if ( fcels ( port, id, handler ) != 0 ) - return 1; + /** Issue ELS */ + if ( ( rc = fcels ( opts.port, id, handler ) ) != 0 ) + return rc; return 0; } diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e475eca5..d505bb6e 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -230,6 +230,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_lotest ( ERRFILE_OTHER | 0x001b0000 ) #define ERRFILE_config_cmd ( ERRFILE_OTHER | 0x001c0000 ) #define ERRFILE_ifmgmt_cmd ( ERRFILE_OTHER | 0x001d0000 ) +#define ERRFILE_fcmgmt_cmd ( ERRFILE_OTHER | 0x001e0000 ) /** @} */ From 1e2a8aa9c1275e0e96df821e94c531cdab438f07 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 19:29:58 +0000 Subject: [PATCH 26/85] [gdb] Use generic option-parsing library Total saving: 42 bytes. Signed-off-by: Michael Brown --- src/hci/commands/gdbstub_cmd.c | 92 ++++++++++++++++++---------------- src/include/ipxe/errfile.h | 1 + 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/hci/commands/gdbstub_cmd.c b/src/hci/commands/gdbstub_cmd.c index 4ad59721..fc9b6fc1 100644 --- a/src/hci/commands/gdbstub_cmd.c +++ b/src/hci/commands/gdbstub_cmd.c @@ -17,8 +17,11 @@ */ #include +#include +#include #include #include +#include #include /** @file @@ -28,71 +31,76 @@ */ /** - * "gdbstub" command syntax message + * Parse GDB transport name * - * @v argv Argument list + * @v text Text + * @ret trans GDB transport + * @ret rc Return status code */ -static void gdbstub_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s [...]\n" - "\n" - "Start remote debugging using one of the following transports:\n" - " serial use serial port (if compiled in)\n" - " udp use UDP over network interface (if compiled in)\n", - argv[0] ); +static int parse_gdb_transport ( const char *text, + struct gdb_transport **trans ) { + + /* Sanity check */ + assert ( text != NULL ); + + /* Find transport */ + *trans = find_gdb_transport ( text ); + if ( ! *trans ) { + printf ( "\"%s\": no such transport (is it compiled in?)\n", + text ); + return -ENOTSUP; + } + + return 0; } +/** "gdbstub" options */ +struct gdbstub_options {}; + +/** "gdbstub" option list */ +static struct option_descriptor gdbstub_opts[] = {}; + +/** "gdbstub" command descriptor */ +static struct command_descriptor gdbstub_cmd = + COMMAND_DESC ( struct gdbstub_options, gdbstub_opts, 1, MAX_ARGUMENTS, + " [...]", + "Start remote debugging using one of the following " + "transports:\n" + " serial use serial port (if compiled in)\n" + " udp use UDP over network interface " + "(if compiled in)" ); + /** * The "gdbstub" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int gdbstub_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - const char *trans_name; + struct gdbstub_options opts; struct gdb_transport *trans; - int c; + int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - gdbstub_syntax ( argv ); - return 1; - } - } + if ( ( rc = parse_options ( argc, argv, &gdbstub_cmd, &opts ) ) != 0 ) + return rc; - /* At least one argument */ - if ( optind == argc ) { - gdbstub_syntax ( argv ); - return 1; - } - - trans_name = argv[optind++]; + /* Parse transport name */ + if ( ( rc = parse_gdb_transport ( argv[optind++], &trans ) ) != 0 ) + return rc; /* Initialise transport */ - trans = find_gdb_transport ( trans_name ); - if ( !trans ) { - printf ( "%s: no such transport (is it compiled in?)\n", trans_name ); - return 1; - } - if ( trans->init ) { - if ( trans->init ( argc - optind, &argv[optind] ) != 0 ) { - return 1; + if ( ( rc = trans->init ( argc - optind, + &argv[optind] ) ) != 0 ) { + return rc; } } /* Enter GDB stub */ gdbstub_start ( trans ); + return 0; } diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index d505bb6e..17e5a4f8 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -231,6 +231,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_config_cmd ( ERRFILE_OTHER | 0x001c0000 ) #define ERRFILE_ifmgmt_cmd ( ERRFILE_OTHER | 0x001d0000 ) #define ERRFILE_fcmgmt_cmd ( ERRFILE_OTHER | 0x001e0000 ) +#define ERRFILE_gdbstub_cmd ( ERRFILE_OTHER | 0x001f0000 ) /** @} */ From ec42ba366f2d5574372aa6f97f5e02964e6d591d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 19:40:32 +0000 Subject: [PATCH 27/85] [lotest] Use generic option-parsing library Total saving: 145 bytes. Signed-off-by: Michael Brown --- src/hci/commands/lotest_cmd.c | 101 ++++++++++++++-------------------- 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/src/hci/commands/lotest_cmd.c b/src/hci/commands/lotest_cmd.c index a2c52bc1..73cefcaa 100644 --- a/src/hci/commands/lotest_cmd.c +++ b/src/hci/commands/lotest_cmd.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include @@ -33,81 +34,63 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -static void lotest_syntax ( char **argv ) { - printf ( "Usage:\n %s \n", - argv[0] ); -} +/** "lotest" options */ +struct lotest_options { + /** MTU */ + unsigned int mtu; +}; +/** "lotest" option list */ +static struct option_descriptor lotest_opts[] = { + OPTION_DESC ( "mtu", 'm', required_argument, + struct lotest_options, mtu, parse_integer ), +}; + +/** "lotest" command descriptor */ +static struct command_descriptor lotest_cmd = + COMMAND_DESC ( struct lotest_options, lotest_opts, 2, 2, + "[--mtu ] " + "", "" ); + +/** + * "lotest" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int lotest_exec ( int argc, char **argv ) { - static struct option lotest_opts[] = { - { "help", 0, NULL, 'h' }, - { "mtu", required_argument, NULL, 'm' }, - { NULL, 0, NULL, 0 }, - }; - const char *sender_name; - const char *receiver_name; - const char *mtu_text = NULL; + struct lotest_options opts; struct net_device *sender; struct net_device *receiver; - char *endp; - size_t mtu; - int c; int rc; - /* Parse command line */ - while ( ( c = getopt_long ( argc, argv, "hm:", lotest_opts, - NULL ) ) >= 0 ) { - switch ( c ) { - case 'm': - mtu_text = optarg; - break; - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - lotest_syntax ( argv ); - return 1; - } - } - if ( optind != ( argc - 2 ) ) { - lotest_syntax ( argv ); - return 1; - } - sender_name = argv[optind]; - receiver_name = argv[optind + 1]; + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &lotest_cmd, &opts ) ) != 0 ) + return rc; - /* Identify network devices */ - sender = find_netdev ( sender_name ); - if ( ! sender ) { - printf ( "%s: no such interface\n", sender_name ); - return 1; - } - receiver = find_netdev ( receiver_name ); - if ( ! receiver ) { - printf ( "%s: no such interface\n", receiver_name ); - return 1; - } + /* Parse sending interface name */ + if ( ( rc = parse_netdev ( argv[optind], &sender ) ) != 0 ) + return rc; - /* Identify MTU */ - if ( mtu_text ) { - mtu = strtoul ( mtu_text, &endp, 10 ); - if ( *endp ) { - printf ( "%s: invalid MTU\n", mtu_text ); - return 1; - } - } else { - mtu = ETH_MAX_MTU; - } + /* Parse receiving interface name */ + if ( ( rc = parse_netdev ( argv[ optind + 1 ], &receiver ) ) != 0 ) + return rc; + + /* Use default MTU if none specified */ + if ( ! opts.mtu ) + opts.mtu = ETH_MAX_MTU; /* Perform loopback test */ - if ( ( rc = loopback_test ( sender, receiver, mtu ) ) != 0 ) { + if ( ( rc = loopback_test ( sender, receiver, opts.mtu ) ) != 0 ) { printf ( "Test failed: %s\n", strerror ( rc ) ); - return 1; + return rc; } return 0; } +/** Loopback testing commands */ struct command lotest_command __command = { .name = "lotest", .exec = lotest_exec, From 817c5446977647a30ccdff34748ff51046d1078b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 19:48:00 +0000 Subject: [PATCH 28/85] [time] Use generic option-parsing library Total saving: 88 bytes. Signed-off-by: Michael Brown --- src/hci/commands/time_cmd.c | 88 +++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/src/hci/commands/time_cmd.c b/src/hci/commands/time_cmd.c index 5e2612a6..e7ad4a76 100644 --- a/src/hci/commands/time_cmd.c +++ b/src/hci/commands/time_cmd.c @@ -24,24 +24,43 @@ #include #include #include +#include #include #include -static int time_exec ( int argc, char **argv ) { - unsigned long start; - int rc, secs; +/** @file + * + * Time commands + * + */ - if ( argc == 1 || - !strcmp ( argv[1], "--help" ) || - !strcmp ( argv[1], "-h" ) ) - { - printf ( "Usage:\n" - " %s \n" - "\n" - "Time a command\n", - argv[0] ); - return 1; - } +/** "time" options */ +struct time_options {}; + +/** "time" option list */ +static struct option_descriptor time_opts[] = {}; + +/** "time" command descriptor */ +static struct command_descriptor time_cmd = + COMMAND_DESC ( struct time_options, time_opts, 1, MAX_ARGUMENTS, + "", "Time a command" ); + +/** + * "time" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int time_exec ( int argc, char **argv ) { + struct time_options opts; + unsigned long start; + int secs; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &time_cmd, &opts ) ) != 0 ) + return rc; start = currticks(); rc = execv ( argv[1], argv + 1 ); @@ -52,25 +71,39 @@ static int time_exec ( int argc, char **argv ) { return rc; } +/** "time" command */ struct command time_command __command = { .name = "time", .exec = time_exec, }; -static int sleep_exec ( int argc, char **argv ) { - unsigned long start, delay; +/** "sleep" options */ +struct sleep_options {}; + +/** "sleep" option list */ +static struct option_descriptor sleep_opts[] = {}; + +/** "sleep" command descriptor */ +static struct command_descriptor sleep_cmd = + COMMAND_DESC ( struct sleep_options, sleep_opts, 1, 1, + "", "Sleep for seconds" ); + +/** + * "sleep" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int sleep_exec ( int argc, char **argv ) { + struct sleep_options opts; + unsigned long start, delay; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &sleep_cmd, &opts ) ) != 0 ) + return rc; - if ( argc == 1 || - !strcmp ( argv[1], "--help" ) || - !strcmp ( argv[1], "-h" )) - { - printf ( "Usage:\n" - " %s \n" - "\n" - "Sleep for seconds\n", - argv[0] ); - return 1; - } start = currticks(); delay = strtoul ( argv[1], NULL, 0 ) * ticks_per_sec(); while ( ( currticks() - start ) <= delay ) @@ -78,6 +111,7 @@ static int sleep_exec ( int argc, char **argv ) { return 0; } +/** "sleep" command */ struct command sleep_command __command = { .name = "sleep", .exec = sleep_exec, From 72b4464c8915c9689028ae4428e63a6aedd709b9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 19:55:51 +0000 Subject: [PATCH 29/85] [san] Use generic option-parsing library Total saving: 73 bytes. Signed-off-by: Michael Brown --- src/hci/commands/sanboot_cmd.c | 74 +++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c index ec7f5acf..1f11cc2d 100644 --- a/src/hci/commands/sanboot_cmd.c +++ b/src/hci/commands/sanboot_cmd.c @@ -1,69 +1,77 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + #include #include #include #include +#include #include FILE_LICENCE ( GPL2_OR_LATER ); -/** - * "sanboot" command syntax message +/** @file + * + * SAN commands * - * @v argv Argument list */ -static void sanboot_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s \n" - "\n" - "Boot from SAN target\n", - argv[0] ); -} + +/** "sanboot" options */ +struct sanboot_options {}; + +/** "sanboot" option list */ +static struct option_descriptor sanboot_opts[] = {}; + +/** "sanboot" command descriptor */ +static struct command_descriptor sanboot_cmd = + COMMAND_DESC ( struct sanboot_options, sanboot_opts, 1, 1, + "", "Boot from SAN target" ); /** * The "sanboot" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int sanboot_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - const char *root_path = NULL; - int c; + struct sanboot_options opts; + const char *root_path; int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - sanboot_syntax ( argv ); - return 1; - } - } + if ( ( rc = parse_options ( argc, argv, &sanboot_cmd, &opts ) ) != 0 ) + return rc; - /* Need exactly one image name remaining after the options */ - if ( optind != ( argc - 1 ) ) { - sanboot_syntax ( argv ); - return 1; - } + /* Parse root path */ root_path = argv[optind]; /* Boot from root path */ if ( ( rc = boot_root_path ( root_path ) ) != 0 ) { printf ( "Could not boot from %s: %s\n", root_path, strerror ( rc ) ); - return 1; + return rc; } return 0; } +/** SAN commands */ struct command sanboot_command __command = { .name = "sanboot", .exec = sanboot_exec, From 46116d8d03ea3df73a93c386c2be33fc8be9cde0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 19:58:45 +0000 Subject: [PATCH 30/85] [route] Use generic option-parsing library Total saving: 71 bytes. Signed-off-by: Michael Brown --- src/hci/commands/route_cmd.c | 51 ++++++++++++------------------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/src/hci/commands/route_cmd.c b/src/hci/commands/route_cmd.c index 05734972..a4f5f91d 100644 --- a/src/hci/commands/route_cmd.c +++ b/src/hci/commands/route_cmd.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** @file @@ -29,52 +30,34 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** - * "route" command syntax message - * - * @v argv Argument list - */ -static void route_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s\n" - "\n" - "Displays the routing table\n", - argv[0] ); -} +/** "route" options */ +struct route_options {}; + +/** "route" option list */ +static struct option_descriptor route_opts[] = {}; + +/** "route" command descriptor */ +static struct command_descriptor route_cmd = + COMMAND_DESC ( struct route_options, route_opts, 0, 0, + "", "Display the routing table" ); /** * The "route" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int route_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; - - int c; + struct route_options opts; + int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - route_syntax ( argv ); - return 1; - } - } - - if ( optind != argc ) { - route_syntax ( argv ); - return 1; - } + if ( ( rc = parse_options ( argc, argv, &route_cmd, &opts ) ) != 0 ) + return rc; route(); + return 0; } From 6832f0688f41c9ae6c14faef648627ada856e822 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 20:02:54 +0000 Subject: [PATCH 31/85] [login] Use generic option-parsing library Total cost: 7 bytes. Signed-off-by: Michael Brown --- src/hci/commands/login_cmd.c | 56 ++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/hci/commands/login_cmd.c b/src/hci/commands/login_cmd.c index be847658..ab173937 100644 --- a/src/hci/commands/login_cmd.c +++ b/src/hci/commands/login_cmd.c @@ -1,28 +1,72 @@ +/* + * Copyright (C) 2010 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + #include #include #include +#include #include FILE_LICENCE ( GPL2_OR_LATER ); +/** @file + * + * Login commands + * + */ + +/** "login" options */ +struct login_options {}; + +/** "login" option list */ +static struct option_descriptor login_opts[] = {}; + +/** "login" command descriptor */ +static struct command_descriptor login_cmd = + COMMAND_DESC ( struct login_options, login_opts, 0, 0, + "", "Prompt for login credentials" ); + +/** + * "login" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ static int login_exec ( int argc, char **argv ) { + struct login_options opts; int rc; - if ( argc > 1 ) { - printf ( "Usage: %s\n" - "Prompt for login credentials\n", argv[0] ); - return 1; - } + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &login_cmd, &opts ) ) != 0 ) + return rc; + /* Show login UI */ if ( ( rc = login_ui() ) != 0 ) { printf ( "Could not set credentials: %s\n", strerror ( rc ) ); - return 1; + return rc; } return 0; } +/** Login commands */ struct command login_command __command = { .name = "login", .exec = login_exec, From 0cd6f2c709ed226cc2d9a57d49d0bbdef93ab1e4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 20:38:00 +0000 Subject: [PATCH 32/85] [image] Use generic option-parsing library Total saving: 548 bytes. Signed-off-by: Michael Brown --- src/hci/commands/image_cmd.c | 473 ++++++++++++----------------------- 1 file changed, 157 insertions(+), 316 deletions(-) diff --git a/src/hci/commands/image_cmd.c b/src/hci/commands/image_cmd.c index 74d0ff55..66002226 100644 --- a/src/hci/commands/image_cmd.c +++ b/src/hci/commands/image_cmd.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** @file @@ -34,12 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -enum image_action { - IMG_FETCH = 0, - IMG_LOAD, - IMG_EXEC, -}; - /** * Fill in image command line * @@ -74,74 +69,61 @@ static int imgfill_cmdline ( struct image *image, unsigned int nargs, } } -/** - * "imgfetch"/"module"/"kernel" command syntax message - * - * @v argv Argument list - */ -static void imgfetch_core_syntax ( char **argv, enum image_action action ) { - static const char *actions[] = { - [IMG_FETCH] = "Fetch", - [IMG_LOAD] = "Fetch and load", - [IMG_EXEC] = "Fetch and execute", - }; +/** "imgfetch" options */ +struct imgfetch_options { + /** Image name */ + const char *name; +}; - printf ( "Usage:\n" - " %s [-n|--name ] filename [arguments...]\n" - "\n" - "%s executable/loadable image\n", - argv[0], actions[action] ); -} +/** "imgfetch" option list */ +static struct option_descriptor imgfetch_opts[] = { + OPTION_DESC ( "name", 'n', required_argument, + struct imgfetch_options, name, parse_string ), +}; + +/** "imgfetch" command descriptor */ +static struct command_descriptor imgfetch_cmd = + COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS, + "[--name ] [...]", + "Fetch image" ); + +/** "kernel" command descriptor */ +static struct command_descriptor kernel_cmd = + COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS, + "[--name ] [...]", + "Fetch and load image" ); + +/** "chain" command descriptor */ +static struct command_descriptor chain_cmd = + COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS, + "[--name ] [...]", + "Fetch and execute image" ); /** - * The "imgfetch"/"module"/"kernel" command body + * The "imgfetch" and friends command body * - * @v image_type Image type to assign (or NULL) - * @v load Image will be automatically loaded after fetching * @v argc Argument count * @v argv Argument list + * @v cmd Command descriptor + * @v image_register Image registration action * @ret rc Return status code */ -static int imgfetch_core_exec ( struct image_type *image_type, - enum image_action action, - int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { "name", required_argument, NULL, 'n' }, - { NULL, 0, NULL, 0 }, - }; +static int imgfetch_core_exec ( int argc, char **argv, + struct command_descriptor *cmd, + int ( * image_register ) ( struct image * ) ) { + struct imgfetch_options opts; struct image *image; - const char *name = NULL; - char *filename; - int ( * image_register ) ( struct image *image ); - int c; + char *uri_string; int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "hn:", - longopts, NULL ) ) >= 0 ) { - switch ( c ) { - case 'n': - /* Set image name */ - name = optarg; - break; - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - imgfetch_core_syntax ( argv, action ); - return -EINVAL; - } - } + if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 ) + return rc; - /* Need at least a filename remaining after the options */ - if ( optind == argc ) { - imgfetch_core_syntax ( argv, action ); - return -EINVAL; - } - filename = argv[optind++]; - if ( ! name ) - name = basename ( filename ); + /* Parse URI string */ + uri_string = argv[optind]; + if ( ! opts.name ) + opts.name = basename ( uri_string ); /* Allocate image */ image = alloc_image(); @@ -151,37 +133,18 @@ static int imgfetch_core_exec ( struct image_type *image_type, } /* Fill in image name */ - if ( name ) { - if ( ( rc = image_set_name ( image, name ) ) != 0 ) - return rc; - } - - /* Set image type (if specified) */ - image->type = image_type; + if ( ( rc = image_set_name ( image, opts.name ) ) != 0 ) + return rc; /* Fill in command line */ - if ( ( rc = imgfill_cmdline ( image, ( argc - optind ), - &argv[optind] ) ) != 0 ) + if ( ( rc = imgfill_cmdline ( image, ( argc - optind - 1 ), + &argv[ optind + 1 ] ) ) != 0 ) return rc; /* Fetch the image */ - switch ( action ) { - case IMG_FETCH: - image_register = register_image; - break; - case IMG_LOAD: - image_register = register_and_autoload_image; - break; - case IMG_EXEC: - image_register = register_and_autoexec_image; - break; - default: - assert ( 0 ); - return -EINVAL; - } - if ( ( rc = imgfetch ( image, filename, image_register ) ) != 0 ) { + if ( ( rc = imgfetch ( image, uri_string, image_register ) ) != 0 ) { printf ( "Could not fetch %s: %s\n", - filename, strerror ( rc ) ); + uri_string, strerror ( rc ) ); image_put ( image ); return rc; } @@ -195,16 +158,12 @@ static int imgfetch_core_exec ( struct image_type *image_type, * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int imgfetch_exec ( int argc, char **argv ) { - int rc; - if ( ( rc = imgfetch_core_exec ( NULL, IMG_FETCH, - argc, argv ) ) != 0 ) - return rc; - - return 0; + return imgfetch_core_exec ( argc, argv, &imgfetch_cmd, + register_image ); } /** @@ -212,15 +171,12 @@ static int imgfetch_exec ( int argc, char **argv ) { * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int kernel_exec ( int argc, char **argv ) { - int rc; - if ( ( rc = imgfetch_core_exec ( NULL, IMG_LOAD, argc, argv ) ) != 0 ) - return rc; - - return 0; + return imgfetch_core_exec ( argc, argv, &kernel_cmd, + register_and_autoload_image ); } /** @@ -228,327 +184,211 @@ static int kernel_exec ( int argc, char **argv ) { * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int chain_exec ( int argc, char **argv) { - int rc; - if ( ( rc = imgfetch_core_exec ( NULL, IMG_EXEC, argc, argv ) ) != 0 ) - return rc; - - return 0; + return imgfetch_core_exec ( argc, argv, &chain_cmd, + register_and_autoexec_image ); } -/** - * "imgload" command syntax message - * - * @v argv Argument list - */ -static void imgload_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s \n" - "\n" - "Load executable/loadable image\n", - argv[0] ); -} +/** "imgload" options */ +struct imgload_options {}; + +/** "imgload" option list */ +static struct option_descriptor imgload_opts[] = {}; + +/** "imgload" command descriptor */ +static struct command_descriptor imgload_cmd = + COMMAND_DESC ( struct imgload_options, imgload_opts, 1, 1, + "", "Load image" ); /** * The "imgload" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int imgload_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; + struct imgload_options opts; struct image *image; - const char *name; - int c; int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - imgload_syntax ( argv ); - return 1; - } - } + if ( ( rc = parse_options ( argc, argv, &imgload_cmd, &opts ) ) != 0 ) + return rc; - /* Need exactly one image name remaining after the options */ - if ( optind != ( argc - 1 ) ) { - imgload_syntax ( argv ); - return 1; - } - name = argv[optind]; + /* Parse image name */ + if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) + return rc; - /* Load all specified images */ - image = find_image ( name ); - if ( ! image ) { - printf ( "No such image: %s\n", name ); - return 1; - } + /* Load image */ if ( ( rc = imgload ( image ) ) != 0 ) { - printf ( "Could not load %s: %s\n", name, strerror ( rc ) ); + printf ( "Could not load %s: %s\n", + image->name, strerror ( rc ) ); return rc; } return 0; } -/** - * "imgargs" command syntax message - * - * @v argv Argument list - */ -static void imgargs_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s [...]\n" - "\n" - "Set arguments for executable/loadable image\n", - argv[0] ); -} +/** "imgargs" options */ +struct imgargs_options {}; + +/** "imgargs" option list */ +static struct option_descriptor imgargs_opts[] = {}; + +/** "imgargs" command descriptor */ +static struct command_descriptor imgargs_cmd = + COMMAND_DESC ( struct imgargs_options, imgargs_opts, 1, MAX_ARGUMENTS, + " [...]", + "Set arguments for image" ); /** * The "imgargs" command body * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int imgargs_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; + struct imgargs_options opts; struct image *image; - const char *name; - int c; int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - imgargs_syntax ( argv ); - return 1; - } - } - - /* Need at least an image name remaining after the options */ - if ( optind == argc ) { - imgargs_syntax ( argv ); - return 1; - } - name = argv[optind++]; - - /* Fill in command line */ - image = find_image ( name ); - if ( ! image ) { - printf ( "No such image: %s\n", name ); - return 1; - } - if ( ( rc = imgfill_cmdline ( image, ( argc - optind ), - &argv[optind] ) ) != 0 ) + if ( ( rc = parse_options ( argc, argv, &imgargs_cmd, &opts ) ) != 0 ) return rc; + /* Parse image name */ + if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) + return rc; + + /* Fill in command line */ + if ( ( rc = imgfill_cmdline ( image, ( argc - optind - 1 ), + &argv[ optind + 1 ] ) ) != 0 ) + return rc; return 0; } -/** - * "imgexec" command syntax message - * - * @v argv Argument list - */ -static void imgexec_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s \n" - "\n" - "Execute executable/loadable image\n", - argv[0] ); -} +/** "imgexec" options */ +struct imgexec_options {}; + +/** "imgexec" option list */ +static struct option_descriptor imgexec_opts[] = {}; + +/** "imgexec" command descriptor */ +static struct command_descriptor imgexec_cmd = + COMMAND_DESC ( struct imgexec_options, imgexec_opts, 0, 1, + "[]", "Execute image" ); /** * The "imgexec" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int imgexec_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; + struct imgexec_options opts; struct image *image; - const char *name = NULL; - int c; int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - imgexec_syntax ( argv ); - return 1; - } - } + if ( ( rc = parse_options ( argc, argv, &imgexec_cmd, &opts ) ) != 0 ) + return rc; - /* Need no more than one image name */ - if ( optind != argc ) - name = argv[optind++]; - if ( optind != argc ) { - imgexec_syntax ( argv ); - return 1; - } - - /* Execute specified image */ - if ( name ) { - image = find_image ( name ); - if ( ! image ) { - printf ( "No such image: %s\n", name ); - return 1; - } + /* Parse image name */ + if ( optind < argc ) { + if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) + return rc; } else { image = imgautoselect(); if ( ! image ) { printf ( "No (unique) loaded image\n" ); - return 1; + return -ENOTTY; } } + /* Execute image */ if ( ( rc = imgexec ( image ) ) != 0 ) { printf ( "Could not execute %s: %s\n", image->name, strerror ( rc ) ); - return 1; + return rc; } return 0; } -/** - * "imgstat" command syntax message - * - * @v argv Argument list - */ -static void imgstat_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s\n" - "\n" - "List executable/loadable images\n", - argv[0] ); -} +/** "imgstat" options */ +struct imgstat_options {}; + +/** "imgstat" option list */ +static struct option_descriptor imgstat_opts[] = {}; + +/** "imgstat" command descriptor */ +static struct command_descriptor imgstat_cmd = + COMMAND_DESC ( struct imgstat_options, imgstat_opts, 0, 0, + "", "List images" ); /** * The "imgstat" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int imgstat_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; + struct imgstat_options opts; struct image *image; - int c; + int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - imgstat_syntax ( argv ); - return 1; - } - } - - /* No arguments */ - if ( optind != argc ) { - imgstat_syntax ( argv ); - return 1; - } + if ( ( rc = parse_options ( argc, argv, &imgstat_cmd, &opts ) ) != 0 ) + return rc; /* Show status of all images */ for_each_image ( image ) { imgstat ( image ); } + return 0; } -/** - * "imgstat" command syntax message - * - * @v argv Argument list - */ -static void imgfree_syntax ( char **argv ) { - printf ( "Usage:\n" - " %s []\n" - "\n" - "Free one or all executable/loadable images\n", - argv[0] ); -} +/** "imgfree" options */ +struct imgfree_options {}; + +/** "imgfree" option list */ +static struct option_descriptor imgfree_opts[] = {}; + +/** "imgfree" command descriptor */ +static struct command_descriptor imgfree_cmd = + COMMAND_DESC ( struct imgfree_options, imgfree_opts, 0, 1, + "[]", "Free image(s)" ); /** * The "imgfree" command * * @v argc Argument count * @v argv Argument list - * @ret rc Exit code + * @ret rc Return status code */ static int imgfree_exec ( int argc, char **argv ) { - static struct option longopts[] = { - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, - }; + struct imgfree_options opts; struct image *image; struct image *tmp; - const char *name = NULL; - int c; + int rc; /* Parse options */ - while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ - switch ( c ) { - case 'h': - /* Display help text */ - default: - /* Unrecognised/invalid option */ - imgfree_syntax ( argv ); - return 1; - } - } + if ( ( rc = parse_options ( argc, argv, &imgfree_cmd, &opts ) ) != 0 ) + return rc; - /* Need no more than one image name */ - if ( optind != argc ) - name = argv[optind++]; - if ( optind != argc ) { - imgfree_syntax ( argv ); - return 1; - } - - if ( name ) { - /* Free specified image (may leak) */ - image = find_image ( name ); - if ( ! image ) { - printf ( "No such image: %s\n", name ); - return 1; - } + if ( optind < argc ) { + /* Free specified image */ + if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) + return rc; imgfree ( image ); } else { /* Free all images */ @@ -556,6 +396,7 @@ static int imgfree_exec ( int argc, char **argv ) { imgfree ( image ); } } + return 0; } From fdd42fa950818fa5494421500125f1841c916c7c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 23:35:50 +0000 Subject: [PATCH 33/85] [legal] Add some missing FILE_LICENCE declarations Signed-off-by: Michael Brown --- src/hci/commands/digest_cmd.c | 2 ++ src/hci/commands/gdbstub_cmd.c | 2 ++ src/hci/commands/time_cmd.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/hci/commands/digest_cmd.c b/src/hci/commands/digest_cmd.c index 99c196a1..d40e8e7d 100644 --- a/src/hci/commands/digest_cmd.c +++ b/src/hci/commands/digest_cmd.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include #include #include diff --git a/src/hci/commands/gdbstub_cmd.c b/src/hci/commands/gdbstub_cmd.c index fc9b6fc1..b0e3ade8 100644 --- a/src/hci/commands/gdbstub_cmd.c +++ b/src/hci/commands/gdbstub_cmd.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include #include #include diff --git a/src/hci/commands/time_cmd.c b/src/hci/commands/time_cmd.c index e7ad4a76..b8af15ff 100644 --- a/src/hci/commands/time_cmd.c +++ b/src/hci/commands/time_cmd.c @@ -19,6 +19,8 @@ * Shao Miller . */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include #include #include From b91116e072c1dfad4f4acfd3dc89347ea5dd913c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2010 23:40:40 +0000 Subject: [PATCH 34/85] [pxe] Remove startpxe and stoppxe commands from default builds These commands exist primarily for debugging and are not generally useful, so save 137 bytes by removing them by default. Signed-off-by: Michael Brown --- src/config/defaults/pcbios.h | 1 - src/config/general.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 165ee14c..7846f8f0 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -28,7 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define PXE_STACK /* PXE stack in iPXE - required for PXELINUX */ #define PXE_MENU /* PXE menu booting */ -#define PXE_CMD /* PXE commands */ #define SANBOOT_PROTO_ISCSI /* iSCSI protocol */ #define SANBOOT_PROTO_AOE /* AoE protocol */ diff --git a/src/config/general.h b/src/config/general.h index b84707ab..c10312a1 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -124,7 +124,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #undef DIGEST_CMD /* Image crypto digest commands */ #undef LOTEST_CMD /* Loopback testing commands */ #undef VLAN_CMD /* VLAN commands */ -//#undef PXE_CMD /* PXE commands */ +#undef PXE_CMD /* PXE commands */ /* * Error message tables to include From 9ba988809d2bae422fe36d5e6c8563b3cd6cac55 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 22 Nov 2010 01:47:07 +0000 Subject: [PATCH 35/85] [cmdline] Add trivial logical operators to iPXE command lines Make the "||" and "&&" operators available within iPXE commands. For example: dhcp net0 || set net0/ip 192.168.0.2 would attempt to acquire an IP address via DHCP, falling back to a static address if DHCP fails. As a side-effect, comments may now be appended to any line. For example: dhcp net0 || set net0/ip 192.168.0.2 # Try DHCP first, then static Signed-off-by: Michael Brown --- src/core/exec.c | 151 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 115 insertions(+), 36 deletions(-) diff --git a/src/core/exec.c b/src/core/exec.c index 7e866325..20b97a6d 100644 --- a/src/core/exec.c +++ b/src/core/exec.c @@ -58,12 +58,12 @@ int execv ( const char *command, char * const argv[] ) { /* Count number of arguments */ for ( argc = 0 ; argv[argc] ; argc++ ) {} + /* An empty command is deemed to do nothing, successfully */ + if ( command == NULL ) + return 0; + /* Sanity checks */ - if ( ! command ) { - DBG ( "No command\n" ); - return -EINVAL; - } - if ( ! argc ) { + if ( argc == 0 ) { DBG ( "%s: empty argument list\n", command ); return -EINVAL; } @@ -156,39 +156,102 @@ static char * expand_command ( const char *command ) { } /** - * Split command line into argv array + * Split command line into tokens * - * @v args Command line - * @v argv Argument array to populate, or NULL - * @ret argc Argument count + * @v command Command line + * @v tokens Token list to populate, or NULL + * @ret count Number of tokens * - * Splits the command line into whitespace-delimited arguments. If @c - * argv is non-NULL, any whitespace in the command line will be + * Splits the command line into whitespace-delimited tokens. If @c + * tokens is non-NULL, any whitespace in the command line will be * replaced with NULs. */ -static int split_args ( char *args, char * argv[] ) { - int argc = 0; +static int split_command ( char *command, char **tokens ) { + int count = 0; while ( 1 ) { /* Skip over any whitespace / convert to NUL */ - while ( isspace ( *args ) ) { - if ( argv ) - *args = '\0'; - args++; + while ( isspace ( *command ) ) { + if ( tokens ) + *command = '\0'; + command++; } /* Check for end of line */ - if ( ! *args ) + if ( ! *command ) break; /* We have found the start of the next argument */ - if ( argv ) - argv[argc] = args; - argc++; + if ( tokens ) + tokens[count] = command; + count++; /* Skip to start of next whitespace, if any */ - while ( *args && ! isspace ( *args ) ) { - args++; + while ( *command && ! isspace ( *command ) ) { + command++; } } - return argc; + return count; +} + +/** + * Terminate command unconditionally + * + * @v rc Status of previous command + * @ret terminate Terminate command + */ +static int terminate_always ( int rc __unused ) { + return 1; +} + +/** + * Terminate command only if previous command succeeded + * + * @v rc Status of previous command + * @ret terminate Terminate command + */ +static int terminate_on_success ( int rc ) { + return ( rc == 0 ); +} + +/** + * Terminate command only if previous command failed + * + * @v rc Status of previous command + * @ret terminate Terminate command + */ +static int terminate_on_failure ( int rc ) { + return ( rc != 0 ); +} + +/** + * Find command terminator + * + * @v tokens Token list + * @ret terminator Terminator type + * @ret argc Argument count + */ +static int command_terminator ( char **tokens, + int ( **terminator ) ( int rc ) ) { + unsigned int i; + + /* Find first terminating token */ + for ( i = 0 ; tokens[i] ; i++ ) { + if ( tokens[i][0] == '#' ) { + /* Start of a comment */ + *terminator = terminate_always; + return i; + } else if ( strcmp ( tokens[i], "||" ) == 0 ) { + /* Short-circuit logical OR */ + *terminator = terminate_on_success; + return i; + } else if ( strcmp ( tokens[i], "&&" ) == 0 ) { + /* Short-circuit logical AND */ + *terminator = terminate_on_failure; + return i; + } + } + + /* End of token list */ + *terminator = terminate_always; + return i; } /** @@ -200,30 +263,46 @@ static int split_args ( char *args, char * argv[] ) { * Execute the named command and arguments. */ int system ( const char *command ) { - char *args; + int ( * terminator ) ( int rc ); + char *expcmd; + char **argv; int argc; + int count; int rc = 0; /* Perform variable expansion */ - args = expand_command ( command ); - if ( ! args ) + expcmd = expand_command ( command ); + if ( ! expcmd ) return -ENOMEM; - /* Count arguments */ - argc = split_args ( args, NULL ); + /* Count tokens */ + count = split_command ( expcmd, NULL ); - /* Create argv array and execute command */ - if ( argc ) { - char * argv[argc + 1]; + /* Create token array */ + if ( count ) { + char * tokens[count + 1]; - split_args ( args, argv ); - argv[argc] = NULL; + split_command ( expcmd, tokens ); + tokens[count] = NULL; - if ( argv[0][0] != '#' ) + for ( argv = tokens ; ; argv += ( argc + 1 ) ) { + + /* Find command terminator */ + argc = command_terminator ( argv, &terminator ); + + /* Execute command */ + argv[argc] = NULL; rc = execv ( argv[0], argv ); + + /* Handle terminator */ + if ( terminator ( rc ) ) + break; + } } - free ( args ); + /* Free expanded command */ + free ( expcmd ); + return rc; } From 6d68ffee396af30c14b971ea677ba6e790695926 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 22 Nov 2010 04:19:24 +0000 Subject: [PATCH 36/85] [script] Implement "goto" in iPXE scripts Allow script labels to be defined using the syntax : (nothing else allowed on the line, including whitespace). Labels are ignored during script execution, but can be used as the target of the "goto" command. For example: #!ipxe goto machine_${net0/ip} || goto machine_default # Linux kernel boot :machine_10.0.0.101 :machine_10.0.0.102 set filename http://my.boot.server/vmlinuz goto done # Default configuration :machine_default set filename pxelinux.0 goto done # Boot selected configuration :done chain ${filename} Originally-implemented-by: Shao Miller Originally-implemented-by: Stefan Hajnoczi Signed-off-by: Michael Brown --- src/image/script.c | 224 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 194 insertions(+), 30 deletions(-) diff --git a/src/image/script.c b/src/image/script.c index b65fa061..ba098c2c 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -27,12 +27,119 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include +#include +#include +#include #include struct image_type script_image_type __image_type ( PROBE_NORMAL ); +/** Currently running script + * + * This is a global in order to allow goto_exec() to update the + * offset. + */ +static struct image *script; + +/** Offset within current script + * + * This is a global in order to allow goto_exec() to update the + * offset. + */ +static size_t script_offset; + +/** + * Process script lines + * + * @v process_line Line processor + * @v terminate Termination check + * @ret rc Return status code + */ +static int process_script ( int ( * process_line ) ( const char *line ), + int ( * terminate ) ( int rc ) ) { + off_t eol; + size_t len; + int rc; + + script_offset = 0; + + do { + + /* Find length of next line, excluding any terminating '\n' */ + eol = memchr_user ( script->data, script_offset, '\n', + ( script->len - script_offset ) ); + if ( eol < 0 ) + eol = script->len; + len = ( eol - script_offset ); + + /* Copy line, terminate with NUL, and execute command */ + { + char cmdbuf[ len + 1 ]; + + copy_from_user ( cmdbuf, script->data, + script_offset, len ); + cmdbuf[len] = '\0'; + DBG ( "$ %s\n", cmdbuf ); + + /* Move to next line */ + script_offset += ( len + 1 ); + + /* Process line */ + rc = process_line ( cmdbuf ); + if ( terminate ( rc ) ) + return rc; + } + + } while ( script_offset < script->len ); + + return rc; +} + +/** + * Terminate script processing if line processing failed + * + * @v rc Line processing status + * @ret terminate Terminate script processing + */ +static int terminate_on_failure ( int rc ) { + return ( rc != 0 ); +} + +/** + * Terminate script processing if line processing succeeded + * + * @v rc Line processing status + * @ret terminate Terminate script processing + */ +static int terminate_on_success ( int rc ) { + return ( rc == 0 ); +} + +/** + * Execute script line + * + * @v line Line of script + * @ret rc Return status code + */ +static int script_exec_line ( const char *line ) { + int rc; + + /* Skip label lines */ + if ( line[0] == ':' ) + return 0; + + /* Execute command */ + if ( ( rc = system ( line ) ) != 0 ) { + printf ( "Aborting on \"%s\"\n", line ); + return rc; + } + + return 0; +} + /** * Execute script * @@ -40,9 +147,8 @@ struct image_type script_image_type __image_type ( PROBE_NORMAL ); * @ret rc Return status code */ static int script_exec ( struct image *image ) { - size_t offset = 0; - off_t eol; - size_t len; + struct image *saved_script; + size_t saved_offset; int rc; /* Temporarily de-register image, so that a "boot" command @@ -50,36 +156,19 @@ static int script_exec ( struct image *image ) { */ unregister_image ( image ); - while ( offset < image->len ) { - - /* Find length of next line, excluding any terminating '\n' */ - eol = memchr_user ( image->data, offset, '\n', - ( image->len - offset ) ); - if ( eol < 0 ) - eol = image->len; - len = ( eol - offset ); + /* Preserve state of any currently-running script */ + saved_script = script; + saved_offset = script_offset; - /* Copy line, terminate with NUL, and execute command */ - { - char cmdbuf[ len + 1 ]; + /* Initialise state for this script */ + script = image; - copy_from_user ( cmdbuf, image->data, offset, len ); - cmdbuf[len] = '\0'; - DBG ( "$ %s\n", cmdbuf ); - if ( ( rc = system ( cmdbuf ) ) != 0 ) { - DBG ( "Command \"%s\" failed: %s\n", - cmdbuf, strerror ( rc ) ); - goto done; - } - } - - /* Move to next line */ - offset += ( len + 1 ); - } + /* Process script */ + rc = process_script ( script_exec_line, terminate_on_failure ); - rc = 0; - done: - /* Re-register image and return */ + /* Restore saved state, re-register image, and return */ + script_offset = saved_offset; + script = saved_script; register_image ( image ); return rc; } @@ -129,3 +218,78 @@ struct image_type script_image_type __image_type ( PROBE_NORMAL ) = { .load = script_load, .exec = script_exec, }; + +/** "goto" options */ +struct goto_options {}; + +/** "goto" option list */ +static struct option_descriptor goto_opts[] = {}; + +/** "goto" command descriptor */ +static struct command_descriptor goto_cmd = + COMMAND_DESC ( struct goto_options, goto_opts, 1, 1, + "