iPXE
ethernet.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
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.
8  *
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.
13  *
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
17  * 02110-1301, USA.
18  *
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.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <byteswap.h>
32 #include <errno.h>
33 #include <assert.h>
34 #include <ipxe/if_arp.h>
35 #include <ipxe/if_ether.h>
36 #include <ipxe/in.h>
37 #include <ipxe/netdevice.h>
38 #include <ipxe/iobuf.h>
39 #include <ipxe/ethernet.h>
40 
41 /** @file
42  *
43  * Ethernet protocol
44  *
45  */
46 
47 /** Ethernet broadcast MAC address */
48 uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
49 
50 /**
51  * Check if Ethernet packet has an 802.3 LLC header
52  *
53  * @v ethhdr Ethernet header
54  * @ret is_llc Packet has 802.3 LLC header
55  */
56 static inline int eth_is_llc_packet ( struct ethhdr *ethhdr ) {
57  uint8_t len_msb;
58 
59  /* Check if the protocol field contains a value short enough
60  * to be a frame length. The slightly convoluted form of the
61  * comparison is designed to reduce to a single x86
62  * instruction.
63  */
64  len_msb = *( ( uint8_t * ) &ethhdr->h_protocol );
65  return ( len_msb < 0x06 );
66 }
67 
68 /**
69  * Add Ethernet link-layer header
70  *
71  * @v netdev Network device
72  * @v iobuf I/O buffer
73  * @v ll_dest Link-layer destination address
74  * @v ll_source Source link-layer address
75  * @v net_proto Network-layer protocol, in network-byte order
76  * @ret rc Return status code
77  */
78 int eth_push ( struct net_device *netdev __unused, struct io_buffer *iobuf,
79  const void *ll_dest, const void *ll_source,
81  struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
82 
83  /* Build Ethernet header */
84  memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
85  memcpy ( ethhdr->h_source, ll_source, ETH_ALEN );
86  ethhdr->h_protocol = net_proto;
87 
88  return 0;
89 }
90 
91 /**
92  * Remove Ethernet link-layer header
93  *
94  * @v netdev Network device
95  * @v iobuf I/O buffer
96  * @ret ll_dest Link-layer destination address
97  * @ret ll_source Source link-layer address
98  * @ret net_proto Network-layer protocol, in network-byte order
99  * @ret flags Packet flags
100  * @ret rc Return status code
101  */
102 int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
103  const void **ll_dest, const void **ll_source,
104  uint16_t *net_proto, unsigned int *flags ) {
105  struct ethhdr *ethhdr = iobuf->data;
106  uint16_t *llc_proto;
107 
108  /* Sanity check. While in theory we could receive a one-byte
109  * packet, this will never happen in practice and performing
110  * the combined length check here avoids the need for an
111  * additional comparison if we detect an LLC frame.
112  */
113  if ( iob_len ( iobuf ) < ( sizeof ( *ethhdr ) + sizeof ( *llc_proto ))){
114  DBG ( "Ethernet packet too short (%zd bytes)\n",
115  iob_len ( iobuf ) );
116  return -EINVAL;
117  }
118 
119  /* Strip off Ethernet header */
120  iob_pull ( iobuf, sizeof ( *ethhdr ) );
121 
122  /* Fill in required fields */
123  *ll_dest = ethhdr->h_dest;
124  *ll_source = ethhdr->h_source;
125  *net_proto = ethhdr->h_protocol;
127  LL_MULTICAST : 0 ) |
129  LL_BROADCAST : 0 ) );
130 
131  /* If this is an LLC frame (with a length in place of the
132  * protocol field), then use the next two bytes (which happen
133  * to be the LLC DSAP and SSAP) as the protocol. This allows
134  * for minimal-overhead support for receiving (rare) LLC
135  * frames, without requiring a full LLC protocol layer.
136  */
137  if ( eth_is_llc_packet ( ethhdr ) ) {
138  llc_proto = iobuf->data;
139  *net_proto = *llc_proto;
140  }
141 
142  return 0;
143 }
144 
145 /**
146  * Initialise Ethernet address
147  *
148  * @v hw_addr Hardware address
149  * @v ll_addr Link-layer address
150  */
151 void eth_init_addr ( const void *hw_addr, void *ll_addr ) {
152  memcpy ( ll_addr, hw_addr, ETH_ALEN );
153 }
154 
155 /**
156  * Generate random Ethernet address
157  *
158  * @v hw_addr Generated hardware address
159  */
160 void eth_random_addr ( void *hw_addr ) {
161  uint8_t *addr = hw_addr;
162  unsigned int i;
163 
164  for ( i = 0 ; i < ETH_ALEN ; i++ )
165  addr[i] = random();
166  addr[0] &= ~0x01; /* Clear multicast bit */
167  addr[0] |= 0x02; /* Set locally-assigned bit */
168 }
169 
170 /**
171  * Transcribe Ethernet address
172  *
173  * @v ll_addr Link-layer address
174  * @ret string Link-layer address in human-readable format
175  */
176 const char * eth_ntoa ( const void *ll_addr ) {
177  static char buf[18]; /* "00:00:00:00:00:00" */
178  const uint8_t *eth_addr = ll_addr;
179 
180  sprintf ( buf, "%02x:%02x:%02x:%02x:%02x:%02x",
181  eth_addr[0], eth_addr[1], eth_addr[2],
182  eth_addr[3], eth_addr[4], eth_addr[5] );
183  return buf;
184 }
185 
186 /**
187  * Hash multicast address
188  *
189  * @v af Address family
190  * @v net_addr Network-layer address
191  * @v ll_addr Link-layer address to fill in
192  * @ret rc Return status code
193  */
194 int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) {
195  const uint8_t *net_addr_bytes = net_addr;
196  uint8_t *ll_addr_bytes = ll_addr;
197 
198  switch ( af ) {
199  case AF_INET:
200  ll_addr_bytes[0] = 0x01;
201  ll_addr_bytes[1] = 0x00;
202  ll_addr_bytes[2] = 0x5e;
203  ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f;
204  ll_addr_bytes[4] = net_addr_bytes[2];
205  ll_addr_bytes[5] = net_addr_bytes[3];
206  return 0;
207  case AF_INET6:
208  ll_addr_bytes[0] = 0x33;
209  ll_addr_bytes[1] = 0x33;
210  memcpy ( &ll_addr_bytes[2], &net_addr_bytes[12], 4 );
211  return 0;
212  default:
213  return -ENOTSUP;
214  }
215 }
216 
217 /**
218  * Generate Ethernet-compatible compressed link-layer address
219  *
220  * @v ll_addr Link-layer address
221  * @v eth_addr Ethernet-compatible address to fill in
222  */
223 int eth_eth_addr ( const void *ll_addr, void *eth_addr ) {
224  memcpy ( eth_addr, ll_addr, ETH_ALEN );
225  return 0;
226 }
227 
228 /**
229  * Generate EUI-64 address
230  *
231  * @v ll_addr Link-layer address
232  * @v eui64 EUI-64 address to fill in
233  * @ret rc Return status code
234  */
235 int eth_eui64 ( const void *ll_addr, void *eui64 ) {
236 
237  memcpy ( ( eui64 + 0 ), ( ll_addr + 0 ), 3 );
238  memcpy ( ( eui64 + 5 ), ( ll_addr + 3 ), 3 );
239  *( ( uint16_t * ) ( eui64 + 3 ) ) = htons ( 0xfffe );
240  return 0;
241 }
242 
243 /** Ethernet protocol */
244 struct ll_protocol ethernet_protocol __ll_protocol = {
245  .name = "Ethernet",
246  .ll_proto = htons ( ARPHRD_ETHER ),
247  .hw_addr_len = ETH_ALEN,
248  .ll_addr_len = ETH_ALEN,
249  .ll_header_len = ETH_HLEN,
250  .push = eth_push,
251  .pull = eth_pull,
252  .init_addr = eth_init_addr,
253  .ntoa = eth_ntoa,
254  .mc_hash = eth_mc_hash,
255  .eth_addr = eth_eth_addr,
256  .eui64 = eth_eui64,
257 };
258 
259 /**
260  * Allocate Ethernet device
261  *
262  * @v priv_size Size of driver private data
263  * @ret netdev Network device, or NULL
264  */
265 struct net_device * alloc_etherdev ( size_t priv_size ) {
266  struct net_device *netdev;
267 
268  netdev = alloc_netdev ( priv_size );
269  if ( netdev ) {
270  netdev->ll_protocol = &ethernet_protocol;
274  }
275  return netdev;
276 }
277 
278 /* Drag in objects via ethernet_protocol */
279 REQUIRING_SYMBOL ( ethernet_protocol );
280 
281 /* Drag in Ethernet configuration */
282 REQUIRE_OBJECT ( config_ethernet );
#define LL_MULTICAST
Packet is a multicast (including broadcast) packet.
Definition: netdevice.h:106
uint16_t h_protocol
Protocol ID.
Definition: if_ether.h:38
#define iob_pull(iobuf, len)
Definition: iobuf.h:107
#define EINVAL
Invalid argument.
Definition: errno.h:429
unsigned short uint16_t
Definition: stdint.h:11
struct ll_protocol ethernet_protocol __ll_protocol
Ethernet protocol.
Definition: ethernet.c:244
#define AF_INET6
IPv6 Internet addresses.
Definition: socket.h:65
int eth_eth_addr(const void *ll_addr, void *eth_addr)
Generate Ethernet-compatible compressed link-layer address.
Definition: ethernet.c:223
Error codes.
#define iob_push(iobuf, len)
Definition: iobuf.h:89
I/O buffers.
#define sprintf(buf, fmt,...)
Write a formatted string to a buffer.
Definition: stdio.h:37
size_t mtu
Maximum transmission unit length.
Definition: netdevice.h:416
uint8_t eth_broadcast[ETH_ALEN]
Ethernet broadcast MAC address.
Definition: ethernet.c:48
REQUIRING_SYMBOL(ethernet_protocol)
const uint8_t * ll_broadcast
Link-layer broadcast address.
Definition: netdevice.h:390
#define ETH_MAX_MTU
Definition: if_ether.h:15
int eth_push(struct net_device *netdev __unused, struct io_buffer *iobuf, const void *ll_dest, const void *ll_source, uint16_t net_proto)
Add Ethernet link-layer header.
Definition: ethernet.c:78
void eth_init_addr(const void *hw_addr, void *ll_addr)
Initialise Ethernet address.
Definition: ethernet.c:151
A link-layer protocol.
Definition: netdevice.h:115
Address Resolution Protocol constants and types.
int eth_eui64(const void *ll_addr, void *eui64)
Generate EUI-64 address.
Definition: ethernet.c:235
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)
Remove Ethernet link-layer header.
Definition: ethernet.c:102
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
struct net_device * alloc_netdev(size_t priv_len)
Allocate network device.
Definition: netdevice.c:722
const char * name
Protocol name.
Definition: netdevice.h:117
uint8_t h_dest[ETH_ALEN]
Destination MAC address.
Definition: if_ether.h:34
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define ETH_HLEN
Definition: if_ether.h:10
Assertions.
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
Ethernet protocol.
#define ETH_FRAME_LEN
Definition: if_ether.h:12
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
static struct net_device * netdev
Definition: gdbudp.c:52
static int eth_is_llc_packet(struct ethhdr *ethhdr)
Check if Ethernet packet has an 802.3 LLC header.
Definition: ethernet.c:56
int eth_mc_hash(unsigned int af, const void *net_addr, void *ll_addr)
Hash multicast address.
Definition: ethernet.c:194
static int is_multicast_ether_addr(const void *addr)
Check if Ethernet address is a multicast address.
Definition: ethernet.h:38
FILE_SECBOOT(PERMITTED)
uint8_t flags
Flags.
Definition: ena.h:18
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition: ethernet.c:176
uint32_t addr
Buffer address.
Definition: dwmac.h:20
A network device.
Definition: netdevice.h:353
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:32
unsigned char uint8_t
Definition: stdint.h:10
uint8_t h_source[ETH_ALEN]
Source MAC address.
Definition: if_ether.h:36
uint16_t net_proto
Network-layer protocol.
Definition: netdevice.h:100
#define ETH_ALEN
Definition: if_ether.h:9
#define LL_BROADCAST
Packet is a broadcast packet.
Definition: netdevice.h:109
Network device management.
void * data
Start of data.
Definition: iobuf.h:53
static int is_broadcast_ether_addr(const void *addr)
Check if Ethernet address is the broadcast address.
Definition: ethernet.h:62
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition: ethernet.c:265
size_t max_pkt_len
Maximum packet length.
Definition: netdevice.h:410
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define ARPHRD_ETHER
Ethernet 10Mbps.
Definition: if_arp.h:17
An Ethernet link-layer header.
Definition: if_ether.h:32
REQUIRE_OBJECT(config_ethernet)
String functions.
#define htons(value)
Definition: byteswap.h:136
#define AF_INET
IPv4 Internet addresses.
Definition: socket.h:64
void eth_random_addr(void *hw_addr)
Generate random Ethernet address.
Definition: ethernet.c:160
struct ll_protocol * ll_protocol
Link-layer protocol.
Definition: netdevice.h:373
A persistent I/O buffer.
Definition: iobuf.h:38