|
@@ -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 * ) ðhdr->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 = ( ðhdr->h_protocol + 1 );
|
|
138
|
+ *net_proto = *llc_proto;
|
|
139
|
+ }
|
|
140
|
+
|
107
|
141
|
return 0;
|
108
|
142
|
}
|
109
|
143
|
|