Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[ethernet] Add minimal support for receiving LLC frames
In some Ethernet framing variants the two-byte protocol field is used
as a length, with the Ethernet header being followed by an IEEE 802.2
LLC header.  The first two bytes of the LLC header are the DSAP and
SSAP.

If the received Ethernet packet appears to use this framing, then
interpret the two-byte DSAP and SSAP as being the network-layer
protocol.  This allows support for receiving Spanning Tree Protocol
frames (which use an LLC header with {DSAP,SSAP}=0x4242) to be added
without requiring a full LLC protocol layer.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Jun 25, 2015
1 parent 36817ea commit 7e78709
Showing 1 changed file with 36 additions and 2 deletions.
38 changes: 36 additions & 2 deletions src/net/ethernet.c
Expand Up @@ -46,6 +46,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Ethernet broadcast MAC address */
uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

/**
* Check if Ethernet packet has an 802.3 LLC header
*
* @v ethhdr Ethernet header
* @ret is_llc Packet has 802.3 LLC header
*/
static inline int eth_is_llc_packet ( struct ethhdr *ethhdr ) {
uint8_t len_msb;

/* Check if the protocol field contains a value short enough
* to be a frame length. The slightly convoluted form of the
* comparison is designed to reduce to a single x86
* instruction.
*/
len_msb = *( ( uint8_t * ) &ethhdr->h_protocol );
return ( len_msb < 0x06 );
}

/**
* Add Ethernet link-layer header
*
Expand Down Expand Up @@ -84,9 +102,14 @@ int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
const void **ll_dest, const void **ll_source,
uint16_t *net_proto, unsigned int *flags ) {
struct ethhdr *ethhdr = iobuf->data;
uint16_t *llc_proto;

/* Sanity check */
if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) {
/* Sanity check. While in theory we could receive a one-byte
* packet, this will never happen in practice and performing
* the combined length check here avoids the need for an
* additional comparison if we detect an LLC frame.
*/
if ( iob_len ( iobuf ) < ( sizeof ( *ethhdr ) + sizeof ( *llc_proto ))){
DBG ( "Ethernet packet too short (%zd bytes)\n",
iob_len ( iobuf ) );
return -EINVAL;
Expand All @@ -104,6 +127,17 @@ int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
LL_BROADCAST : 0 ) );

/* If this is an LLC frame (with a length in place of the
* protocol field), then use the next two bytes (which happen
* to be the LLC DSAP and SSAP) as the protocol. This allows
* for minimal-overhead support for receiving (rare) LLC
* frames, without requiring a full LLC protocol layer.
*/
if ( eth_is_llc_packet ( ethhdr ) ) {
llc_proto = ( &ethhdr->h_protocol + 1 );
*net_proto = *llc_proto;
}

return 0;
}

Expand Down

0 comments on commit 7e78709

Please sign in to comment.