Browse Source

[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>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
7e7870984b
1 changed files with 36 additions and 2 deletions
  1. 36
    2
      src/net/ethernet.c

+ 36
- 2
src/net/ethernet.c View File

@@ -46,6 +46,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
46 46
 /** Ethernet broadcast MAC address */
47 47
 uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
48 48
 
49
+/**
50
+ * Check if Ethernet packet has an 802.3 LLC header
51
+ *
52
+ * @v ethhdr		Ethernet header
53
+ * @ret is_llc		Packet has 802.3 LLC header
54
+ */
55
+static inline int eth_is_llc_packet ( struct ethhdr *ethhdr ) {
56
+	uint8_t len_msb;
57
+
58
+	/* Check if the protocol field contains a value short enough
59
+	 * to be a frame length.  The slightly convoluted form of the
60
+	 * comparison is designed to reduce to a single x86
61
+	 * instruction.
62
+	 */
63
+	len_msb = *( ( uint8_t * ) &ethhdr->h_protocol );
64
+	return ( len_msb < 0x06 );
65
+}
66
+
49 67
 /**
50 68
  * Add Ethernet link-layer header
51 69
  *
@@ -84,9 +102,14 @@ int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
84 102
 	       const void **ll_dest, const void **ll_source,
85 103
 	       uint16_t *net_proto, unsigned int *flags ) {
86 104
 	struct ethhdr *ethhdr = iobuf->data;
105
+	uint16_t *llc_proto;
87 106
 
88
-	/* Sanity check */
89
-	if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) {
107
+	/* Sanity check.  While in theory we could receive a one-byte
108
+	 * packet, this will never happen in practice and performing
109
+	 * the combined length check here avoids the need for an
110
+	 * additional comparison if we detect an LLC frame.
111
+	 */
112
+	if ( iob_len ( iobuf ) < ( sizeof ( *ethhdr ) + sizeof ( *llc_proto ))){
90 113
 		DBG ( "Ethernet packet too short (%zd bytes)\n",
91 114
 		      iob_len ( iobuf ) );
92 115
 		return -EINVAL;
@@ -104,6 +127,17 @@ int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
104 127
 		   ( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
105 128
 		     LL_BROADCAST : 0 ) );
106 129
 
130
+	/* If this is an LLC frame (with a length in place of the
131
+	 * protocol field), then use the next two bytes (which happen
132
+	 * to be the LLC DSAP and SSAP) as the protocol.  This allows
133
+	 * for minimal-overhead support for receiving (rare) LLC
134
+	 * frames, without requiring a full LLC protocol layer.
135
+	 */
136
+	if ( eth_is_llc_packet ( ethhdr ) ) {
137
+		llc_proto = ( &ethhdr->h_protocol + 1 );
138
+		*net_proto = *llc_proto;
139
+	}
140
+
107 141
 	return 0;
108 142
 }
109 143
 

Loading…
Cancel
Save