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

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
gPXE-devel mailing list
[email protected]
http://etherboot.org/mailman/listinfo/gpxe-devel

Reply via email to