Subject: Re: kern/32644: gsip(4) sends byte-swapped vlan tags
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Pavel Cahyna <pcah8322@artax.karlin.mff.cuni.cz>
List: netbsd-bugs
Date: 01/30/2006 15:20:02
The following reply was made to PR kern/32644; it has been noted by GNATS.

From: Pavel Cahyna <pcah8322@artax.karlin.mff.cuni.cz>
To: gnats-bugs@netbsd.org
Cc: kern-bug-people@netbsd.org, gnats-admin@netbsd.org,
	netbsd-bugs@netbsd.org
Subject: Re: kern/32644: gsip(4) sends byte-swapped vlan tags
Date: Mon, 30 Jan 2006 16:15:54 +0100

 On Fri, Jan 27, 2006 at 03:35:02AM +0000, Christos Zoulas wrote:
 >  | --- if_sip.c.~1.101.~	Sun Feb 27 01:27:33 2005
 >  | +++ if_sip.c	Wed Jan 25 00:51:11 2006
 >  | @@ -1354,10 +1354,20 @@
 >  |  		 * This apparently has to be on the last descriptor of
 >  |  		 * the packet.
 >  |  		 */
 >  | +
 >  | +		/*
 >  | +		 * Byte swapping is tricky. We need to provide the tag
 >  | +		 * in a network byte order. On a big-endian machine,
 >  | +		 * the byteorder is correct, but we need to swap it
 >  | +		 * anyway, because this will be undone by the outside
 >  | +		 * htole32(). That's why there must be an
 >  | +		 * unconditional swap instead of htons() inside.
 >  | +		 */
 >  |  		if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) {
 >  |  			sc->sc_txdescs[lasttx].sipd_extsts |=
 >  | -			    htole32(EXTSTS_VPKT |
 >  | -				    (VLAN_TAG_VALUE(mtag) & EXTSTS_VTCI));
 >  | +			    htole32(EXTSTS_VPKT | 
 >  | +					(bswap16(VLAN_TAG_VALUE(mtag)) &
 >  | +					 EXTSTS_VTCI));
 >  |  		}
 >  |  
 >  |  		/*
 >  | @@ -1969,8 +1979,19 @@
 >  |  		 * If VLANs are enabled, VLAN packets have been unwrapped
 >  |  		 * for us.  Associate the tag with the packet.
 >  |  		 */
 >  | +
 >  | +		/*
 >  | +		 * Again, byte swapping is tricky. Hardware provided
 >  | +		 * the tag in the network byte order, but extsts was
 >  | +		 * passed through le32toh() in the meantime. On a
 >  | +		 * big-endian machine, we need to swap it again. On a
 >  | +		 * little-endian machine, we need to convert from the
 >  | +		 * network to host byte order. This means that we must
 >  | +		 * swap it in any case, so unconditional swap instead
 >  | +		 * of htons() is used.
 >  | +		 */
 >  |  		if ((extsts & EXTSTS_VPKT) != 0) {
 >  | -			VLAN_INPUT_TAG(ifp, m, ntohs(extsts & EXTSTS_VTCI),
 >  | +			VLAN_INPUT_TAG(ifp, m, bswap16(extsts & EXTSTS_VTCI),
 >  |  			    continue);
 >  |  		}
 >  |  
 >  -- End of excerpt from Pavel Cahyna
 >  
 >  
 >  This does not seem right because in the first part of the patch you do:
 >  
 >  +			    htole32(EXTSTS_VPKT | 
 >  +					(bswap16(VLAN_TAG_VALUE(mtag)) &
 >  +					 EXTSTS_VTCI));
 >  
 >  and in the second:
 >  
 >  | +			VLAN_INPUT_TAG(ifp, m, bswap16(extsts & EXTSTS_VTCI),
 >  
 >  because in the first patch you are not bswapping16 EXTSTS_VTCI and in the
 >  second you do?
 
 I think it can be justified algebraically:
 
 The firts patched part does:
 
 mtag(host byte order) -> bswap16 -> &= EXTSTS_VTCI -> |= EXTSTS_VPKT ->
 -> htole32 -> tx descriptor
 
 while the second does:
 
 rx descriptor -> le32toh -> &= EXTSTS_VTCI -> bswap16 -> mtag(host byte
 order)
 
 So, the second sequence is inverse to the first.
 
 Pavel