diff --git a/src/core/config.c b/src/core/config.c index b501ea55..19deec5b 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -152,6 +152,9 @@ REQUIRE_OBJECT ( nvo_cmd ); #ifdef CONFIG_CMD REQUIRE_OBJECT ( config_cmd ); #endif +#ifdef IFMGMT_CMD +REQUIRE_OBJECT ( ifmgmt_cmd ); +#endif /* * Drag in miscellaneous objects diff --git a/src/hci/commands/ifmgmt_cmd.c b/src/hci/commands/ifmgmt_cmd.c new file mode 100644 index 00000000..fde5fbb1 --- /dev/null +++ b/src/hci/commands/ifmgmt_cmd.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2007 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 + * + * Network interface management commands + * + */ + +/** 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; + + /* Print error if no network devices exist */ + if ( ! have_netdevs() ) { + printf ( "No network interfaces\n" ); + return 1; + } + + /* 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; +} + +/** + * Execute if command + * + * @v payload Command to execute + * @v verb Verb describing the action of the command + * @v argc Argument count + * @v argv Argument list + * @ret rc Exit code + */ +static __attribute__ (( regparm ( 2 ) )) int +ifcommon_exec ( int ( * payload ) ( struct net_device * ), + const char *verb, int argc, char **argv ) { + int c; + + /* 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 ( optind == argc ) { + return ifcommon_do_all ( payload ); + } else { + return ifcommon_do_list ( payload, &argv[optind], + ( argc - optind ) ); + } +} + +/* "ifopen" command */ + +static int ifopen_payload ( struct net_device *netdev ) { + return ifopen ( netdev ); +} + +static int ifopen_exec ( int argc, char **argv ) { + return ifcommon_exec ( ifopen_payload, "Open", argc, argv ); +} + +struct command ifopen_command __command = { + .name = "ifopen", + .exec = ifopen_exec, +}; + +/* "ifclose" command */ + +static int ifclose_payload ( struct net_device *netdev ) { + ifclose ( netdev ); + return 0; +} + +static int ifclose_exec ( int argc, char **argv ) { + return ifcommon_exec ( ifclose_payload, "Close", argc, argv ); +} + +struct command ifclose_command __command = { + .name = "ifclose", + .exec = ifclose_exec, +}; + +/* "ifstat" command */ + +static int ifstat_payload ( struct net_device *netdev ) { + ifstat ( netdev ); + return 0; +} + +static int ifstat_exec ( int argc, char **argv ) { + return ifcommon_exec ( ifstat_payload, "Display status of", + argc, argv ); +} + +struct command ifstat_command __command = { + .name = "ifstat", + .exec = ifstat_exec, +}; diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 90d03fcf..e1dddd63 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -224,6 +224,8 @@ struct net_device { /** Declare a network-layer protocol */ #define __net_protocol __table ( net_protocols, 01 ) +extern struct list_head net_devices; + /** * Get printable network device hardware address * @@ -234,6 +236,18 @@ static inline const char * netdev_hwaddr ( struct net_device *netdev ) { return netdev->ll_protocol->ntoa ( netdev->ll_addr ); } +/** Iterate over all network devices */ +#define for_each_netdev( netdev ) \ + list_for_each_entry ( (netdev), &net_devices, list ) + +/** There exist some network devices + * + * @ret existence Existence of network devices + */ +static inline int have_netdevs ( void ) { + return ( ! list_empty ( &net_devices ) ); +} + extern int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb ); void netdev_tx_complete ( struct net_device *netdev, struct pk_buff *pkb ); void netdev_tx_complete_next ( struct net_device *netdev ); @@ -247,7 +261,6 @@ extern void netdev_close ( struct net_device *netdev ); extern void unregister_netdev ( struct net_device *netdev ); extern void free_netdev ( struct net_device *netdev ); struct net_device * find_netdev ( const char *name ); -extern struct net_device * next_netdev ( void ); extern int net_tx ( struct pk_buff *pkb, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest ); extern int net_rx ( struct pk_buff *pkb, struct net_device *netdev, diff --git a/src/include/usr/ifmgmt.h b/src/include/usr/ifmgmt.h new file mode 100644 index 00000000..c7d35da8 --- /dev/null +++ b/src/include/usr/ifmgmt.h @@ -0,0 +1,16 @@ +#ifndef _USR_IFMGMT_H +#define _USR_IFMGMT_H + +/** @file + * + * Network interface management + * + */ + +struct net_device; + +extern int ifopen ( struct net_device *netdev ); +extern void ifclose ( struct net_device *netdev ); +extern void ifstat ( struct net_device *netdev ); + +#endif /* _USR_IFMGMT_H */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index f3b76a76..8c95afd6 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -40,7 +40,7 @@ static struct net_protocol net_protocols[0] __table_start ( net_protocols ); static struct net_protocol net_protocols_end[0] __table_end ( net_protocols ); /** List of network devices */ -static LIST_HEAD ( net_devices ); +struct list_head net_devices = LIST_HEAD_INIT ( net_devices ); /** * Transmit raw packet via network device @@ -309,26 +309,6 @@ struct net_device * find_netdev ( const char *name ) { return NULL; } -/** - * Iterate through network devices - * - * @ret netdev Network device, or NULL - * - * This returns the registered network devices in the order of - * registration. If no network devices are registered, it will return - * NULL. - */ -struct net_device * next_netdev ( void ) { - struct net_device *netdev; - - list_for_each_entry ( netdev, &net_devices, list ) { - list_del ( &netdev->list ); - list_add_tail ( &netdev->list, &net_devices ); - return netdev; - } - return NULL; -} - /** * Transmit network-layer packet * diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index 0fa4e8e4..5cfde823 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -19,6 +19,7 @@ #include #include #include +#include #include /** @file @@ -27,26 +28,21 @@ * */ -#include void test_dhcp ( struct net_device *netdev ); void autoboot ( void ) { struct net_device *netdev; int rc; - netdev = next_netdev (); - if ( ! netdev ) { - printf ( "No network device found\n" ); - return; + for_each_netdev ( netdev ) { + + if ( ( rc = ifopen ( netdev ) ) != 0 ) + continue; + + test_dhcp ( netdev ); + + ifclose ( netdev ); } - if ( ( rc = netdev_open ( netdev ) ) != 0 ) { - printf ( "Could not open %s: %s\n", netdev->name, - strerror ( rc ) ); - return; - } - - test_dhcp ( netdev ); - - netdev_close ( netdev ); + printf ( "No more network devices\n" ); } diff --git a/src/usr/ifmgmt.c b/src/usr/ifmgmt.c new file mode 100644 index 00000000..32684167 --- /dev/null +++ b/src/usr/ifmgmt.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007 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 + +/** @file + * + * Network interface management + * + */ + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +int ifopen ( struct net_device *netdev ) { + int rc; + + if ( ( rc = netdev_open ( netdev ) ) != 0 ) { + printf ( "Could not open %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Close network device + * + * @v netdev Network device + */ +void ifclose ( struct net_device *netdev ) { + netdev_close ( netdev ); +} + +/** + * Print status of network device + * + * @v netdev Network device + */ +void ifstat ( struct net_device *netdev ) { + printf ( "%s %s %s\n", + netdev->name, netdev_hwaddr ( netdev ), + ( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ) ); +}