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., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <gpxe/if_arp.h>
24 #include <gpxe/if_ether.h>
25 #include <gpxe/netdevice.h>
26 #include <gpxe/pkbuff.h>
28 #include <gpxe/ethernet.h>
36 /** Ethernet broadcast MAC address */
37 static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
40 * Perform Ethernet routing
42 * @v nethdr Generic network-layer header
43 * @ret llhdr Generic link-layer header
44 * @ret rc Return status code
46 * Constructs the generic link-layer header based on the generic
47 * network-layer header, i.e. maps network-layer addresses (e.g. IPv4
48 * addresses) to MAC addresses.
50 * If the destination MAC address cannot be determined, an ARP request
51 * is sent for the requested network-layer address and -ENOENT is
54 static int eth_route ( const struct net_header *nethdr,
55 struct ll_header *llhdr ) {
58 /* Work out the destination MAC address */
59 if ( nethdr->dest_flags & NETADDR_FL_RAW ) {
60 memcpy ( llhdr->dest_ll_addr, nethdr->dest_net_addr, ETH_ALEN);
61 } else if ( nethdr->dest_flags & NETADDR_FL_BROADCAST ) {
62 memcpy ( llhdr->dest_ll_addr, eth_broadcast, ETH_ALEN );
63 } else if ( nethdr->dest_flags & NETADDR_FL_MULTICAST ) {
64 /* IP multicast is a special case; there exists a
65 * direct mapping from IP address to MAC address
67 assert ( nethdr->net_protocol->net_proto == htons(ETH_P_IP) );
68 llhdr->dest_ll_addr[0] = 0x01;
69 llhdr->dest_ll_addr[1] = 0x00;
70 llhdr->dest_ll_addr[2] = 0x5e;
71 llhdr->dest_ll_addr[3] = nethdr->dest_net_addr[1] & 0x7f;
72 llhdr->dest_ll_addr[4] = nethdr->dest_net_addr[2];
73 llhdr->dest_ll_addr[5] = nethdr->dest_net_addr[3];
75 /* Otherwise, look up the address using ARP */
76 if ( ( rc = arp_resolve ( nethdr, llhdr ) ) != 0 )
84 * Fill in Ethernet link-layer header
86 * @v pkb Packet buffer
87 * @v llhdr Generic link-layer header
89 * Fills in the Ethernet link-layer header in the packet buffer based
90 * on information in the generic link-layer header.
92 static void eth_fill_llh ( const struct ll_header *llhdr,
93 struct pk_buff *pkb ) {
94 struct ethhdr *ethhdr = pkb->data;
96 memcpy ( ethhdr->h_dest, llhdr->dest_ll_addr, ETH_ALEN );
97 memcpy ( ethhdr->h_source, llhdr->source_ll_addr, ETH_ALEN );
98 ethhdr->h_protocol = llhdr->net_proto;
102 * Parse Ethernet link-layer header
104 * @v pkb Packet buffer
105 * @v llhdr Generic link-layer header
107 * Fills in the generic link-layer header based on information in the
108 * Ethernet link-layer header in the packet buffer.
110 static void eth_parse_llh ( const struct pk_buff *pkb,
111 struct ll_header *llhdr ) {
112 struct ethhdr *ethhdr = pkb->data;
114 memcpy ( llhdr->dest_ll_addr, ethhdr->h_dest, ETH_ALEN );
115 memcpy ( llhdr->source_ll_addr, ethhdr->h_source, ETH_ALEN );
116 llhdr->net_proto = ethhdr->h_protocol;
118 if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) {
119 llhdr->dest_flags = NETADDR_FL_BROADCAST;
120 } else if ( ethhdr->h_dest[0] & 0x01 ) {
121 llhdr->dest_flags = NETADDR_FL_MULTICAST;
123 llhdr->dest_flags = 0;
127 /** Ethernet protocol */
128 struct ll_protocol ethernet_protocol = {
129 .ll_proto = htons ( ARPHRD_ETHER ),
130 .ll_addr_len = ETH_ALEN,
131 .ll_header_len = ETH_HLEN,
133 .fill_llh = eth_fill_llh,
134 .parse_llh = eth_parse_llh,
137 LL_PROTOCOL ( ethernet_protocol );