2
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License as
6
* published by the Free Software Foundation; either version 2 of the
7
* License, or any later version.
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
* You can also choose to distribute this program under the terms of
20
* the Unmodified Binary Distribution Licence (as given in the file
21
* COPYING.UBDL), provided that you have satisfied its requirements.
24
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
33
#include <ipxe/if_arp.h>
34
#include <ipxe/if_ether.h>
36
#include <ipxe/netdevice.h>
37
#include <ipxe/iobuf.h>
38
#include <ipxe/ethernet.h>
46
/** Ethernet broadcast MAC address */
47
uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
50
* Check if Ethernet packet has an 802.3 LLC header
52
* @v ethhdr Ethernet header
53
* @ret is_llc Packet has 802.3 LLC header
55
static inline int eth_is_llc_packet ( struct ethhdr *ethhdr ) {
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
63
len_msb = *( ( uint8_t * ) ðhdr->h_protocol );
64
return ( len_msb < 0x06 );
68
* Add Ethernet link-layer header
70
* @v netdev Network device
72
* @v ll_dest Link-layer destination address
73
* @v ll_source Source link-layer address
74
* @v net_proto Network-layer protocol, in network-byte order
75
* @ret rc Return status code
77
int eth_push ( struct net_device *netdev __unused, struct io_buffer *iobuf,
78
const void *ll_dest, const void *ll_source,
79
uint16_t net_proto ) {
80
struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
82
/* Build Ethernet header */
83
memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
84
memcpy ( ethhdr->h_source, ll_source, ETH_ALEN );
85
ethhdr->h_protocol = net_proto;
91
* Remove Ethernet link-layer header
93
* @v netdev Network device
95
* @ret ll_dest Link-layer destination address
96
* @ret ll_source Source link-layer address
97
* @ret net_proto Network-layer protocol, in network-byte order
98
* @ret flags Packet flags
99
* @ret rc Return status code
101
int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
102
const void **ll_dest, const void **ll_source,
103
uint16_t *net_proto, unsigned int *flags ) {
104
struct ethhdr *ethhdr = iobuf->data;
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.
112
if ( iob_len ( iobuf ) < ( sizeof ( *ethhdr ) + sizeof ( *llc_proto ))){
113
DBG ( "Ethernet packet too short (%zd bytes)\n",
118
/* Strip off Ethernet header */
119
iob_pull ( iobuf, sizeof ( *ethhdr ) );
121
/* Fill in required fields */
122
*ll_dest = ethhdr->h_dest;
123
*ll_source = ethhdr->h_source;
124
*net_proto = ethhdr->h_protocol;
125
*flags = ( ( is_multicast_ether_addr ( ethhdr->h_dest ) ?
127
( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
128
LL_BROADCAST : 0 ) );
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.
136
if ( eth_is_llc_packet ( ethhdr ) ) {
137
llc_proto = ( ðhdr->h_protocol + 1 );
138
*net_proto = *llc_proto;
145
* Initialise Ethernet address
147
* @v hw_addr Hardware address
148
* @v ll_addr Link-layer address
150
void eth_init_addr ( const void *hw_addr, void *ll_addr ) {
151
memcpy ( ll_addr, hw_addr, ETH_ALEN );
155
* Generate random Ethernet address
157
* @v hw_addr Generated hardware address
159
void eth_random_addr ( void *hw_addr ) {
160
uint8_t *addr = hw_addr;
163
for ( i = 0 ; i < ETH_ALEN ; i++ )
165
addr[0] &= ~0x01; /* Clear multicast bit */
166
addr[0] |= 0x02; /* Set locally-assigned bit */
170
* Transcribe Ethernet address
172
* @v ll_addr Link-layer address
173
* @ret string Link-layer address in human-readable format
175
const char * eth_ntoa ( const void *ll_addr ) {
176
static char buf[18]; /* "00:00:00:00:00:00" */
177
const uint8_t *eth_addr = ll_addr;
179
sprintf ( buf, "%02x:%02x:%02x:%02x:%02x:%02x",
180
eth_addr[0], eth_addr[1], eth_addr[2],
181
eth_addr[3], eth_addr[4], eth_addr[5] );
186
* Hash multicast address
188
* @v af Address family
189
* @v net_addr Network-layer address
190
* @v ll_addr Link-layer address to fill in
191
* @ret rc Return status code
193
int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) {
194
const uint8_t *net_addr_bytes = net_addr;
195
uint8_t *ll_addr_bytes = ll_addr;
199
ll_addr_bytes[0] = 0x01;
200
ll_addr_bytes[1] = 0x00;
201
ll_addr_bytes[2] = 0x5e;
202
ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f;
203
ll_addr_bytes[4] = net_addr_bytes[2];
204
ll_addr_bytes[5] = net_addr_bytes[3];
207
ll_addr_bytes[0] = 0x33;
208
ll_addr_bytes[1] = 0x33;
209
memcpy ( &ll_addr_bytes[2], &net_addr_bytes[12], 4 );
217
* Generate Ethernet-compatible compressed link-layer address
219
* @v ll_addr Link-layer address
220
* @v eth_addr Ethernet-compatible address to fill in
222
int eth_eth_addr ( const void *ll_addr, void *eth_addr ) {
223
memcpy ( eth_addr, ll_addr, ETH_ALEN );
228
* Generate EUI-64 address
230
* @v ll_addr Link-layer address
231
* @v eui64 EUI-64 address to fill in
232
* @ret rc Return status code
234
int eth_eui64 ( const void *ll_addr, void *eui64 ) {
236
memcpy ( ( eui64 + 0 ), ( ll_addr + 0 ), 3 );
237
memcpy ( ( eui64 + 5 ), ( ll_addr + 3 ), 3 );
238
*( ( uint16_t * ) ( eui64 + 3 ) ) = htons ( 0xfffe );
242
/** Ethernet protocol */
243
struct ll_protocol ethernet_protocol __ll_protocol = {
245
.ll_proto = htons ( ARPHRD_ETHER ),
246
.hw_addr_len = ETH_ALEN,
247
.ll_addr_len = ETH_ALEN,
248
.ll_header_len = ETH_HLEN,
251
.init_addr = eth_init_addr,
253
.mc_hash = eth_mc_hash,
254
.eth_addr = eth_eth_addr,
259
* Allocate Ethernet device
261
* @v priv_size Size of driver private data
262
* @ret netdev Network device, or NULL
264
struct net_device * alloc_etherdev ( size_t priv_size ) {
265
struct net_device *netdev;
267
netdev = alloc_netdev ( priv_size );
269
netdev->ll_protocol = ðernet_protocol;
270
netdev->ll_broadcast = eth_broadcast;
271
netdev->max_pkt_len = ETH_FRAME_LEN;
276
/* Drag in objects via ethernet_protocol */
277
REQUIRING_SYMBOL ( ethernet_protocol );
279
/* Drag in Ethernet configuration */
280
REQUIRE_OBJECT ( config_ethernet );