Hi Michael, thanks for that quick reply.
Michael Brown schrieb:
> char name[] in struct net_device may as well be 12 rather than 10, since it's
> going to get dword-aligned anyway.
done
>
> Why is ieee8021q_transmit() creating a new iobuf?
As netdev_tx registers the iobuf in netdev->tx_queue, though
the iobuf cannot be registered in multiple lists, and because in case
of an error, netdev_tx of the raw device freeed the iobuf and netdev_tx
of the vlan device will also free the buffer.
>
> Device open counts should be implemented in net/netdevice.c within
> netdev_open() and netdev_close(); you can use ib_open() and ib_close() in
> net/infiniband.c as a reference.
done
> The NETDEV_OPEN flag must be removed and
> replaced with something like a static inline netdev_is_open() which just
> checks the netdev's open count. This change should probably be in its own
> separate commit.
done
>
> I would try to avoid calling fetch_uintz_setting() for each transmitted
> packet. Better to hold the VLAN tag in a structure member. For example:
>
> struct vlan_device {
> /* Underlying net device */
> struct net_device *netdev;
> /* VLAN tag */
> uint32_t tag;
> };
>
> with the struct vlan_device forming the private data of the net_device you
> create.
done
>
> Lastly, is 802.1Q Ethernet-specific? In that case, you may as well just
> treat
> it as its own static struct ll_protocol, rather than trying to dynamically
> create a ll_protocol based on the underlying net_device. (gPXE isn't really
> set up to handle a struct ll_protocol that might be freed; they're assumed to
> be static and permanent.)
802.1Q can be used with Ethernet and FDDI. For gpxe, I wanted to support
ethernet and 802.11 link layer structs. Anyway, the ll_protocol of
netdev only is setup and freed when the device is created / destroyed,
so nobody should hold a reference to the virtual netdev anymore when the
ll_protocol is freed or changed.
Michael
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/arch/i386/hci/commands/pxe_cmd.c gpxev1/src/arch/i386/hci/commands/pxe_cmd.c
--- gpxe/src/arch/i386/hci/commands/pxe_cmd.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/arch/i386/hci/commands/pxe_cmd.c 2010-03-10 19:11:22.000000000 +0000
@@ -6,7 +6,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
static int startpxe_payload ( struct net_device *netdev ) {
- if ( netdev->state & NETDEV_OPEN )
+ if ( netdev_is_open ( netdev ) )
pxe_activate ( netdev );
return 0;
}
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/arch/i386/interface/pxe/pxe_undi.c gpxev1/src/arch/i386/interface/pxe/pxe_undi.c
--- gpxe/src/arch/i386/interface/pxe/pxe_undi.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/arch/i386/interface/pxe/pxe_undi.c 2010-03-10 19:11:22.000000000 +0000
@@ -366,7 +366,7 @@ pxenv_undi_set_station_address ( struct
/* If adapter is open, the change will have no effect; return
* an error
*/
- if ( pxe_netdev->state & NETDEV_OPEN ) {
+ if ( netdev_is_open ( pxe_netdev ) ) {
DBG ( " failed: netdev is open\n" );
undi_set_station_address->Status =
PXENV_STATUS_UNDI_INVALID_STATE;
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/include/gpxe/netdevice.h gpxev1/src/include/gpxe/netdevice.h
--- gpxe/src/include/gpxe/netdevice.h 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/include/gpxe/netdevice.h 2010-03-10 19:12:10.000000000 +0000
@@ -262,6 +262,8 @@ struct net_device_stats {
struct net_device {
/** Reference counter */
struct refcnt refcnt;
+ /** Open counter */
+ unsigned int opencnt;
/** List of network devices */
struct list_head list;
/** List of open network devices */
@@ -326,9 +328,6 @@ struct net_device {
void *priv;
};
-/** Network device is open */
-#define NETDEV_OPEN 0x0001
-
/** Link-layer protocol table */
#define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" )
@@ -357,6 +356,16 @@ static inline void netdev_init ( struct
}
/**
+ * Test for netdev is open
+ *
+ * @r bool true of open
+ */
+
+static inline int netdev_is_open ( struct net_device *netdev ) {
+ return (netdev->opencnt > 0);
+}
+
+/**
* Stop using a network device
*
* @v netdev Network device
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/interface/efi/efi_snp.c gpxev1/src/interface/efi/efi_snp.c
--- gpxe/src/interface/efi/efi_snp.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/interface/efi/efi_snp.c 2010-03-10 19:11:22.000000000 +0000
@@ -328,7 +328,7 @@ efi_snp_station_address ( EFI_SIMPLE_NET
memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
/* MAC address changes take effect only on netdev_open() */
- if ( snpdev->netdev->state & NETDEV_OPEN ) {
+ if ( netdev_is_open ( snpdev->netdev ) ) {
DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
"devive open\n", snpdev );
}
@@ -713,7 +713,7 @@ static VOID EFIAPI efi_snp_wait_for_pack
DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
/* Do nothing unless the net device is open */
- if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) )
+ if ( ! netdev_is_open( snpdev->netdev ) )
return;
/* Poll the network device */
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/net/80211/net80211.c gpxev1/src/net/80211/net80211.c
--- gpxe/src/net/80211/net80211.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/net/80211/net80211.c 2010-03-10 19:11:22.000000000 +0000
@@ -1304,7 +1304,7 @@ struct net80211_probe_ctx * net80211_pro
if ( ! ctx )
return NULL;
- assert ( dev->netdev->state & NETDEV_OPEN );
+ assert ( netdev_is_open( dev->netdev ) );
ctx->dev = dev;
ctx->old_keep_mgmt = net80211_keep_mgmt ( dev, 1 );
@@ -1908,7 +1908,7 @@ static int net80211_check_settings_updat
int key_reassoc;
list_for_each_entry ( dev, &net80211_devices, list ) {
- if ( ! ( dev->netdev->state & NETDEV_OPEN ) )
+ if ( ! netdev_is_open ( dev->netdev ) )
continue;
key_reassoc = 0;
@@ -2012,7 +2012,7 @@ static void net80211_set_rtscts_rate ( s
*/
void net80211_set_rate_idx ( struct net80211_device *dev, int rate )
{
- assert ( dev->netdev->state & NETDEV_OPEN );
+ assert ( netdev_is_open ( dev->netdev ) );
if ( rate >= 0 && rate < dev->nr_rates && rate != dev->rate ) {
DBGC2 ( dev, "802.11 %p changing rate from %d->%d Mbps\n",
@@ -2035,7 +2035,7 @@ int net80211_change_channel ( struct net
{
int i, oldchan = dev->channel;
- assert ( dev->netdev->state & NETDEV_OPEN );
+ assert ( netdev_is_open ( dev->netdev ) );
for ( i = 0; i < dev->nr_channels; i++ ) {
if ( dev->channels[i].channel_nr == channel ) {
@@ -2064,7 +2064,7 @@ int net80211_change_channel ( struct net
int net80211_prepare_probe ( struct net80211_device *dev, int band,
int active )
{
- assert ( dev->netdev->state & NETDEV_OPEN );
+ assert ( netdev_is_open ( dev->netdev ) );
if ( active && ( band & NET80211_BAND_BIT_5GHZ ) ) {
DBGC ( dev, "802.11 %p cannot perform active scanning on "
@@ -2124,7 +2124,7 @@ int net80211_prepare_assoc ( struct net8
struct net80211_handshaker *handshaker;
int rc;
- assert ( dev->netdev->state & NETDEV_OPEN );
+ assert ( netdev_is_open( dev->netdev ) );
net80211_set_state ( dev, NET80211_ASSOCIATED, 0, 0 );
memcpy ( dev->bssid, wlan->bssid, ETH_ALEN );
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/net/ipv4.c gpxev1/src/net/ipv4.c
--- gpxe/src/net/ipv4.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/net/ipv4.c 2010-03-10 19:11:22.000000000 +0000
@@ -118,7 +118,7 @@ static struct ipv4_miniroute * ipv4_rout
/* Find first usable route in routing table */
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
- if ( ! ( miniroute->netdev->state & NETDEV_OPEN ) )
+ if ( ! netdev_is_open( miniroute->netdev ) )
continue;
local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
& miniroute->netmask.s_addr ) == 0 );
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/net/netdevice.c gpxev1/src/net/netdevice.c
--- gpxe/src/net/netdevice.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/net/netdevice.c 2010-03-10 19:11:22.000000000 +0000
@@ -130,7 +130,7 @@ int netdev_tx ( struct net_device *netde
list_add_tail ( &iobuf->list, &netdev->tx_queue );
- if ( ! ( netdev->state & NETDEV_OPEN ) ) {
+ if ( ! netdev_is_open( netdev ) ) {
rc = -ENETUNREACH;
goto err;
}
@@ -263,7 +263,7 @@ void netdev_rx_err ( struct net_device *
*/
void netdev_poll ( struct net_device *netdev ) {
- if ( netdev->state & NETDEV_OPEN )
+ if ( netdev_is_open( netdev ) )
netdev->op->poll ( netdev );
}
@@ -388,7 +388,7 @@ int netdev_open ( struct net_device *net
int rc;
/* Do nothing if device is already open */
- if ( netdev->state & NETDEV_OPEN )
+ if ( netdev->opencnt++ > 0 )
return 0;
DBGC ( netdev, "NETDEV %p opening\n", netdev );
@@ -397,9 +397,6 @@ int netdev_open ( struct net_device *net
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 );
@@ -414,7 +411,7 @@ int netdev_open ( struct net_device *net
void netdev_close ( struct net_device *netdev ) {
/* Do nothing if device is already closed */
- if ( ! ( netdev->state & NETDEV_OPEN ) )
+ if ( --netdev->opencnt > 0 )
return;
DBGC ( netdev, "NETDEV %p closing\n", netdev );
@@ -426,9 +423,6 @@ void netdev_close ( struct net_device *n
netdev_tx_flush ( netdev );
netdev_rx_flush ( netdev );
- /* Mark as closed */
- netdev->state &= ~NETDEV_OPEN;
-
/* Remove from open devices list */
list_del ( &netdev->open_list );
}
@@ -509,7 +503,7 @@ struct net_device * last_opened_netdev (
struct net_device *netdev;
list_for_each_entry ( netdev, &open_net_devices, open_list ) {
- assert ( netdev->state & NETDEV_OPEN );
+ assert ( netdev_is_open(netdev) );
return netdev;
}
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/usr/ifmgmt.c gpxev1/src/usr/ifmgmt.c
--- gpxe/src/usr/ifmgmt.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/usr/ifmgmt.c 2010-03-10 19:11:22.000000000 +0000
@@ -90,7 +90,7 @@ void ifstat ( struct net_device *netdev
printf ( "%s: %s on %s (%s)\n"
" [Link:%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
netdev->name, netdev_addr ( netdev ), netdev->dev->name,
- ( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ),
+ ( netdev_is_open ( netdev ) ? "open" : "closed" ),
( netdev_link_ok ( netdev ) ? "up" : "down" ),
netdev->tx_stats.good, netdev->tx_stats.bad,
netdev->rx_stats.good, netdev->rx_stats.bad );
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/usr/iwmgmt.c gpxev1/src/usr/iwmgmt.c
--- gpxe/src/usr/iwmgmt.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/usr/iwmgmt.c 2010-03-10 19:11:22.000000000 +0000
@@ -125,7 +125,7 @@ int iwlist ( struct net80211_device *dev
char ssid_buf[22];
int rc;
unsigned i;
- int was_opened = dev->netdev->state & NETDEV_OPEN;
+ int was_opened = netdev_is_open ( dev->netdev );
int was_channel = dev->channels[dev->channel].channel_nr;
if ( ! was_opened ) {
diff -p -u -r --exclude .git --exclude '*.o' gpxe/src/usr/route.c gpxev1/src/usr/route.c
--- gpxe/src/usr/route.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev1/src/usr/route.c 2010-03-10 19:11:22.000000000 +0000
@@ -38,7 +38,7 @@ void route ( void ) {
printf ( "%s", inet_ntoa ( miniroute->netmask ) );
if ( miniroute->gateway.s_addr )
printf ( " gw %s", inet_ntoa ( miniroute->gateway ) );
- if ( ! ( miniroute->netdev->state & NETDEV_OPEN ) )
+ if ( ! netdev_is_open( miniroute->netdev ) )
printf ( " (inaccessible)" );
printf ( "\n" );
}
Binary files gpxev1/src/bin/blib.a and gpxev2/src/bin/blib.a differ
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/config/config.c gpxev2/src/config/config.c
--- gpxev1/src/config/config.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev2/src/config/config.c 2010-03-09 21:35:46.000000000 +0000
@@ -92,6 +92,14 @@ REQUIRE_OBJECT ( ipv4 );
#endif
/*
+ * Drag in 802.1Q support
+ */
+#ifdef NET_8021Q
+REQUIRE_OBJECT(vconfig_cmd);
+REQUIRE_OBJECT(ieee8021q);
+#endif
+
+/*
* Drag in all requested PXE support
*
*/
@@ -234,7 +242,10 @@ REQUIRE_OBJECT ( digest_cmd );
#ifdef PXE_CMD
REQUIRE_OBJECT ( pxe_cmd );
#endif
-
+#ifdef NETBOOT_CMD
+REQUIRE_OBJECT ( netboot_cmd );
+#endif
+/* VCONFIG_CMD is brought by 8021q if requested */
/*
* Drag in miscellaneous objects
*
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/config/general.h gpxev2/src/config/general.h
--- gpxev1/src/config/general.h 2010-03-10 18:56:43.000000000 +0000
+++ gpxev2/src/config/general.h 2010-03-09 15:50:24.000000000 +0000
@@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
#define NET_PROTO_IPV4 /* IPv4 protocol */
+//#undef NET_8021Q /* 802.1Q protocol */
/*
* PXE support
@@ -120,6 +121,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#undef TIME_CMD /* Time commands */
#undef DIGEST_CMD /* Image crypto digest commands */
//#undef PXE_CMD /* PXE commands */
+//#undef NETBOOT_CMD /* netboot commnds, like autoboot for a single device */
/*
* Error message tables to include
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/hci/commands/netboot_cmd.c gpxev2/src/hci/commands/netboot_cmd.c
--- gpxev1/src/hci/commands/netboot_cmd.c 1970-01-01 00:00:00.000000000 +0000
+++ gpxev2/src/hci/commands/netboot_cmd.c 2010-03-10 00:56:14.000000000 +0000
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <gpxe/command.h>
+#include <gpxe/netdevice.h>
+#include <usr/autoboot.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+void netboot_usage(char** argv, char* msg) {
+ printf ( "Usage:\n"
+ " %s <interface>\n"
+ "\n"
+ "Attempts to boot the system\n"
+ "%s\n",
+ argv[0], msg );
+}
+
+static int netboot_exec ( int argc, char **argv ) {
+
+ if (argc != 2) {
+ netboot_usage(argv, "Wrong number of arguments");
+ return 1;
+ }
+
+ struct net_device* netdev = find_netdev(argv[1]);
+ if (!netdev) {
+ netboot_usage(argv, "No such interface.");
+ return 1;
+ }
+
+ netboot(netdev);
+ return 0;
+}
+
+struct command netboot_command __command = {
+ .name = "netboot",
+ .exec = netboot_exec,
+};
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/hci/commands/vconfig_cmd.c gpxev2/src/hci/commands/vconfig_cmd.c
--- gpxev1/src/hci/commands/vconfig_cmd.c 1970-01-01 00:00:00.000000000 +0000
+++ gpxev2/src/hci/commands/vconfig_cmd.c 2010-03-10 19:05:27.000000000 +0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 Michael Brown <[email protected]>.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <strings.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/ieee8021q.h>
+#include <gpxe/command.h>
+
+/** @file
+ *
+ * 801.Q interface management commands
+ *
+ */
+
+/**
+ * Print syntax of vconfig command
+ *
+ * @v argv Command arguments
+ * @v help Error message
+ */
+static void vconfig_syntax ( char **argv, char* help ) {
+ printf ( "Usage:\n"
+ " %s add <interface> vid [prio]\n"
+ " %s rem <interface>\n"
+ "\n"
+ "%s\n",
+ argv[0], argv[0], help );
+}
+
+static int vconfig_exec ( int argc, char **argv ) {
+ struct net_device* netdev = NULL;
+ int vid = 0;
+
+ if (argc < 3) {
+ vconfig_syntax ( argv, "Too few parameters." );
+ return 1;
+ }
+
+ netdev = find_netdev(argv[2]);
+ if (!netdev) {
+ vconfig_syntax ( argv, "No such device." );
+ return 1;
+ }
+
+ if (strcmp("add", argv[1]) == 0) {
+ if (argc < 4) {
+ vconfig_syntax ( argv, "Missing vid." );
+ }
+ vid = strtoul(argv[3],NULL,0);
+ if (vid <= 0 || vid >= 4095) {
+ vconfig_syntax ( argv, "VID must be in range [1,4094]." );
+ return 1;
+ }
+ uint8_t prio = 0;
+ if (argc > 4) {
+ prio = strtoul(argv[4],NULL,0);
+ }
+ if (prio > 7) {
+ vconfig_syntax ( argv, "PRIO must be in range [0,7]." );
+ return 1;
+ }
+ netdev = ieee8021q_create(netdev,vid,prio);
+ if (!netdev) {
+ printf("Failed to create vlan device.\n");
+ return 1;
+ } else {
+ printf("Added device %s\n", netdev->name);
+ }
+ } else if (strcmp("rem", argv[1]) == 0) {
+ ieee8021q_remove(netdev);
+ } else {
+ vconfig_syntax ( argv, "Unknown command." );
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Interface management commands */
+struct command vconfig_commands[] __command = {
+ {
+ .name = "vconfig",
+ .exec = vconfig_exec,
+ },
+};
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/include/gpxe/errfile.h gpxev2/src/include/gpxe/errfile.h
--- gpxev1/src/include/gpxe/errfile.h 2010-03-10 18:56:43.000000000 +0000
+++ gpxev2/src/include/gpxe/errfile.h 2010-03-09 21:34:16.000000000 +0000
@@ -120,6 +120,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_vxge_main ( ERRFILE_DRIVER | 0x00550000 )
#define ERRFILE_vxge_config ( ERRFILE_DRIVER | 0x00560000 )
#define ERRFILE_vxge_traffic ( ERRFILE_DRIVER | 0x00570000 )
+#define ERRFILE_ieee8021q ( ERRFILE_DRIVER | 0x00580000 )
#define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 )
#define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 )
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/include/gpxe/ieee8021q.h gpxev2/src/include/gpxe/ieee8021q.h
--- gpxev1/src/include/gpxe/ieee8021q.h 1970-01-01 00:00:00.000000000 +0000
+++ gpxev2/src/include/gpxe/ieee8021q.h 2010-03-10 18:58:15.000000000 +0000
@@ -0,0 +1,12 @@
+#ifndef _GPXE_8021Q_H
+#define _GPXE_8021Q_H
+
+#include <stdint.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct net_device * ieee8021q_create ( struct net_device* target, uint16_t vid, uint8_t prio );
+void ieee8021q_remove ( struct net_device* netdev);
+
+#endif
+
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/include/gpxe/if_ether_8021q.h gpxev2/src/include/gpxe/if_ether_8021q.h
--- gpxev1/src/include/gpxe/if_ether_8021q.h 1970-01-01 00:00:00.000000000 +0000
+++ gpxev2/src/include/gpxe/if_ether_8021q.h 2010-03-09 17:59:27.000000000 +0000
@@ -0,0 +1,26 @@
+#ifndef _GPXE_IF_ETHER_8021Q_H
+#define _GPXE_IF_ETHER_8021Q_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#define NET_8021Q_CFI_POS 12
+#define NET_8021Q_CFI_LEN 1
+#define NET_8021Q_CFI_VAL 0
+#define NET_8021Q_PRIO_POS 13
+#define NET_8021Q_PRIO_LEN 3
+#define NET_8021Q_VID_POS 0
+#define NET_8021Q_VID_LEN 12
+
+#define NET_8021Q_PROTO 0x8100
+
+/* 802.1Q header */
+struct vlanhdr {
+ /** PRIO (3bit) / CFI (1Bit) / VID (12 Bit) */
+ uint16_t h_8021q;
+ /** Protocol ID */
+ uint16_t h_protocol;
+} __attribute__ ((packed));
+
+
+#endif /* _GPXE_IF_ETHER_8021Q_H */
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/include/gpxe/netdevice.h gpxev2/src/include/gpxe/netdevice.h
--- gpxev1/src/include/gpxe/netdevice.h 2010-03-10 19:12:10.000000000 +0000
+++ gpxev2/src/include/gpxe/netdevice.h 2010-03-10 17:16:55.000000000 +0000
@@ -269,7 +269,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 -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/include/usr/autoboot.h gpxev2/src/include/usr/autoboot.h
--- gpxev1/src/include/usr/autoboot.h 2010-03-10 18:56:43.000000000 +0000
+++ gpxev2/src/include/usr/autoboot.h 2010-03-09 16:24:50.000000000 +0000
@@ -22,4 +22,6 @@ extern int boot_root_path ( const char *
extern int pxe_menu_boot ( struct net_device *netdev )
__attribute__ (( weak ));
+extern int netboot ( struct net_device *netdev );
+
#endif /* _USR_AUTOBOOT_H */
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/net/ieee8021q.c gpxev2/src/net/ieee8021q.c
--- gpxev1/src/net/ieee8021q.c 1970-01-01 00:00:00.000000000 +0000
+++ gpxev2/src/net/ieee8021q.c 2010-03-10 19:05:06.000000000 +0000
@@ -0,0 +1,269 @@
+/* ieee8021q.c - etherboot driver for proxing 802.1Q to other devices
+ *
+ * This driver installs an networkl ayer receiving handler,
+ * which will catch 802.1Q packets from the raw device and instead inject them into a virtual vlan device.
+ * Further, all packets send through the virtual device and then proxied through the link layer of the raw device.
+ * All device actions apply instandly on the raw device.
+ *
+ * (c) Copyright 2010 M. Braun <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <gpxe/if_ether_8021q.h>
+#include <gpxe/ieee8021q.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/malloc.h>
+#include <gpxe/list.h>
+#include <gpxe/iobuf.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+struct vlan_device {
+ struct net_device* netdev; /* the vlan device */
+ struct list_head list;
+};
+
+struct vlan_device_priv {
+ struct net_device* netdev; /* the underlying raw device */
+ uint16_t vlanid;
+ uint8_t prio;
+};
+
+static LIST_HEAD ( ieee8021q_devices );
+
+/** The 802.1Q VLAN-ID to use */
+struct setting ethernet_802_1q_vid_setting __setting = {
+ .name = "vid",
+ .description = "vlan id",
+ .type = &setting_type_uint16,
+};
+
+/** The 802.1P priority to use */
+struct setting ethernet_802_1q_prio_setting __setting = {
+ .name = "prio",
+ .description = "packet priority",
+ .type = &setting_type_uint8,
+};
+
+/* proxy device operations */
+static void ieee8021q_close ( struct net_device* dev ) {
+ return netdev_close(((struct vlan_device_priv*)dev->priv)->netdev);
+}
+
+static int ieee8021q_open ( struct net_device* dev ) {
+ return netdev_open(((struct vlan_device_priv*)dev->priv)->netdev);
+}
+
+static int ieee8021q_transmit ( struct net_device* dev, struct io_buffer* iobuf ) {
+ /* cannot proxy iobuf directly because it includes a list reference! */
+ struct io_buffer* newiobuf = alloc_iob(iob_len(iobuf)+iob_headroom(iobuf)+iob_tailroom(iobuf));
+ if (!newiobuf) return -ENOMEM;
+ void* data = iob_put(newiobuf, iob_len(iobuf));
+ memcpy(data, iobuf->data, iob_len(iobuf));
+ int rc = netdev_tx(((struct vlan_device_priv*)dev->priv)->netdev, newiobuf);
+ if (rc==0) {
+ netdev_tx_complete ( dev, iobuf );
+ } /* otherwise netdev_tx will do so */
+ return rc;
+}
+
+static void ieee8021q_poll ( struct net_device* dev __unused) {
+ netdev_poll(((struct vlan_device_priv*)dev->priv)->netdev);
+}
+
+static void ieee8021q_irq ( struct net_device* dev, int enable ) {
+ /* a little bit unsure about side effects */
+ return netdev_irq(((struct vlan_device_priv*)dev->priv)->netdev, enable);
+}
+
+static struct net_device_operations ieee8021q_operations = {
+ .open = ieee8021q_open,
+ .close = ieee8021q_close,
+ .transmit = ieee8021q_transmit,
+ .poll = ieee8021q_poll,
+ .irq = ieee8021q_irq,
+};
+
+/** Link-Layer Stack */
+
+#define FILTERNBIT(n) ((1 << n)-1)
+
+/**
+ * Add Ethernet link-layer header. This is called on the tagged device.
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
+ */
+static int ieee8021q_push ( struct net_device *netdev,
+ struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source, uint16_t net_proto ) {
+ struct vlanhdr *vlanhdr = iob_push ( iobuf, sizeof ( *vlanhdr ) );
+ struct vlan_device_priv* priv = (struct vlan_device_priv*)netdev->priv;
+
+ vlanhdr->h_8021q = 0;
+ vlanhdr->h_8021q |= (priv->prio & FILTERNBIT(NET_8021Q_PRIO_LEN)) << NET_8021Q_PRIO_POS;
+ vlanhdr->h_8021q |= (priv->vlanid & FILTERNBIT(NET_8021Q_VID_LEN)) << NET_8021Q_VID_POS;
+ vlanhdr->h_8021q |= (NET_8021Q_CFI_VAL & FILTERNBIT(NET_8021Q_CFI_LEN)) << NET_8021Q_CFI_POS;
+ vlanhdr->h_8021q = htons(vlanhdr->h_8021q);
+ vlanhdr->h_protocol = net_proto;
+
+ return priv->netdev->ll_protocol->push(priv->netdev, iobuf, ll_dest, ll_source, htons(NET_8021Q_PROTO));
+}
+
+/**
+ * Remove Ethernet link-layer header. This is called on raw device which can receive tagged and untagged packets.
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
+ */
+static int ieee8021q_pull ( struct io_buffer *iobuf, struct net_device *netdev,
+ const void *ll_source) {
+ struct vlanhdr *vlanhdr = iobuf->data;
+
+ if ( iob_len ( iobuf ) < sizeof(*vlanhdr) ) {
+ DBG ( "VLAN packet too short (%zd bytes)\n",
+ iob_len ( iobuf ) );
+ goto err;
+ }
+
+ /* Strip off VLAN header */
+ iob_pull ( iobuf, sizeof(*vlanhdr) );
+
+ const unsigned int incomingvid = (htons(vlanhdr->h_8021q) >> NET_8021Q_VID_POS) & FILTERNBIT(NET_8021Q_VID_LEN);
+ if (incomingvid <= 0 || incomingvid >= 4095) {
+ DBG("Bad vlan id %d on wire\n", incomingvid);
+ goto err;
+ }
+
+ struct vlan_device* vdev;
+ list_for_each_entry(vdev, &ieee8021q_devices, list) {
+ struct vlan_device_priv* vlan_device_priv = (struct vlan_device_priv*) vdev->netdev->priv;
+ const unsigned int vid = vlan_device_priv->vlanid;
+
+ if (incomingvid != vid || vid <= 0 || vid >= 4095 || netdev != vlan_device_priv->netdev)
+ continue;
+
+ DBG("inject into %s with proto %X\n", vdev->netdev->name, vlanhdr->h_protocol);
+ if (! netdev_is_open(vdev->netdev)) goto err;
+
+ return net_rx ( iobuf, vdev->netdev, vlanhdr->h_protocol, ll_source);
+
+ }
+err:
+ free_iob(iobuf);
+ return -EINVAL;
+}
+
+static const char * vid_ntoa ( const void *net_addr ) {
+ static char buf[2]; /* "00" */
+ const uint8_t eth_addr = * (uint8_t*)net_addr;
+
+ sprintf ( buf, "%02x", eth_addr);
+ return buf;
+}
+
+/** 802.1Q protocol */
+struct net_protocol ieee8021q_protocol __net_protocol = {
+ .name = "802.1Q",
+ .net_proto = htons ( NET_8021Q_PROTO ),
+ .net_addr_len = 2,
+ .rx = ieee8021q_pull,
+ .ntoa = vid_ntoa,
+};
+
+/** Initialisation and Remove */
+
+struct net_device * ieee8021q_create ( struct net_device* target, uint16_t vid, uint8_t prio ) {
+ struct net_device* netdev = alloc_netdev( 0 );
+
+ if (!netdev)
+ return 0;
+
+ netdev_init ( netdev, &ieee8021q_operations );
+
+ netdev->ll_protocol = zalloc(sizeof(*target->ll_protocol));
+ if (!netdev->ll_protocol)
+ goto err_register_llprotocol;
+ memcpy(netdev->ll_protocol,target->ll_protocol, sizeof(*target->ll_protocol));
+ netdev->ll_protocol->push = ieee8021q_push;
+
+ netdev->ll_broadcast = target->ll_broadcast;
+ netdev->max_pkt_len = target->max_pkt_len;
+ memcpy(netdev->hw_addr,target->hw_addr,sizeof(netdev->hw_addr));
+ netdev->state = target->state;
+
+ snprintf ( netdev->name, sizeof ( netdev->name ), "%s.%d", target->name, vid);
+
+ /* Mark as link up; we don't yet handle link state */
+ netdev_link_up ( netdev );
+
+ /* Register network device */
+ if ( register_netdev ( netdev ) != 0 )
+ goto err_register_netdev;
+
+ /* write-back ll_addr init */
+ memcpy(netdev->ll_addr,target->ll_addr,sizeof(netdev->ll_addr));
+
+ /* add netdev to list */
+ struct vlan_device* vdev = zalloc(sizeof(*vdev));
+ vdev->netdev = netdev;
+ list_add(&vdev->list, &ieee8021q_devices);
+
+ /* set target device */
+ struct vlan_device_priv* priv = zalloc(sizeof(*priv));
+ priv->netdev = netdev_get(target);
+ priv->vlanid = vid;
+ priv->prio = prio;
+ netdev->priv = priv;
+
+ DBG("Added device %s.\n", netdev->name);
+
+ return netdev;
+
+ err_register_netdev:
+ free(netdev->ll_protocol);
+ err_register_llprotocol:
+ netdev_put( netdev->priv );
+ netdev->priv = NULL;
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ return 0;
+}
+
+void ieee8021q_remove ( struct net_device* netdev) {
+ if (netdev->op->open != ieee8021q_open) {
+ DBG("Sorry, but this does not look like a ieee8021q device.\n"
+ "So I won't remove it!\n");
+ return;
+ }
+
+ struct vlan_device* vdev;
+ list_for_each_entry(vdev, &ieee8021q_devices, list) {
+ if (vdev->netdev == netdev) {
+ list_del(&vdev->list);
+ }
+ }
+
+ unregister_netdev ( netdev );
+ free(netdev->ll_protocol);
+ netdev->ll_protocol = NULL;
+ struct vlan_device_priv* vlan_device_priv = (struct vlan_device_priv*) netdev->priv;
+ netdev_put( vlan_device_priv->netdev );
+ free (vlan_device_priv);
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/net/netdevice.c gpxev2/src/net/netdevice.c
--- gpxev1/src/net/netdevice.c 2010-03-10 19:11:22.000000000 +0000
+++ gpxev2/src/net/netdevice.c 2010-03-10 17:09:31.000000000 +0000
@@ -354,8 +354,10 @@ int register_netdev ( struct net_device
int rc;
/* Create device name */
- snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
+ if (strlen(netdev->name) < 1 || find_netdev(netdev->name)) {
+ 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 );
@@ -561,8 +563,9 @@ int net_rx ( struct io_buffer *iobuf, st
/* Hand off to network-layer protocol, if any */
for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
- if ( net_protocol->net_proto == net_proto )
+ if ( net_protocol->net_proto == net_proto ) {
return net_protocol->rx ( iobuf, netdev, ll_source );
+ }
}
DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n",
@@ -602,7 +605,8 @@ static void net_step ( struct process *p
*/
if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
- DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n",
+ DBGC ( netdev, "NETDEV %s %p processing %p (%p+%zx)\n",
+ netdev->name,
netdev, iobuf, iobuf->data,
iob_len ( iobuf ) );
diff -N -p -u -r --exclude console.h --exclude .git --exclude serial.h --exclude image.h --exclude '*.o' --exclude '*.list' --exclude '*.d' --exclude '*.lkrn' --exclude zbin --exclude '*.tmp' --exclude '*.map' --exclude '*.state' gpxev1/src/usr/autoboot.c gpxev2/src/usr/autoboot.c
--- gpxev1/src/usr/autoboot.c 2010-03-10 18:56:43.000000000 +0000
+++ gpxev2/src/usr/autoboot.c 2010-03-09 16:30:48.000000000 +0000
@@ -128,7 +128,7 @@ int boot_root_path ( const char *root_pa
* @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
signature.asc
Description: OpenPGP digital signature
_______________________________________________ gPXE-devel mailing list [email protected] http://etherboot.org/mailman/listinfo/gpxe-devel
