Network API now allows for multiple network devices (although the
[people/oremanj/gpxe.git] / src / net / ethernet.c
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdint.h>
20 #include <string.h>
21 #include <byteswap.h>
22 #include <assert.h>
23 #include <gpxe/if_arp.h>
24 #include <gpxe/if_ether.h>
25 #include <gpxe/netdevice.h>
26 #include <gpxe/pkbuff.h>
27 #include <gpxe/arp.h>
28 #include <gpxe/ethernet.h>
29
30 /** @file
31  *
32  * Ethernet protocol
33  *
34  */
35
36 /** Ethernet broadcast MAC address */
37 static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
38
39 /**
40  * Perform Ethernet routing
41  *
42  * @v nethdr    Generic network-layer header
43  * @ret llhdr   Generic link-layer header
44  * @ret rc      Return status code
45  *
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.
49  *
50  * If the destination MAC address cannot be determined, an ARP request
51  * is sent for the requested network-layer address and -ENOENT is
52  * returned.
53  */
54 static int eth_route ( const struct net_header *nethdr,
55                        struct ll_header *llhdr ) {
56         int rc;
57
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
66                  */
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];
74         } else {
75                 /* Otherwise, look up the address using ARP */
76                 if ( ( rc = arp_resolve ( nethdr, llhdr ) ) != 0 )
77                         return rc;
78         }
79
80         return 0;
81 }
82
83 /**
84  * Fill in Ethernet link-layer header
85  *
86  * @v pkb       Packet buffer
87  * @v llhdr     Generic link-layer header
88  *
89  * Fills in the Ethernet link-layer header in the packet buffer based
90  * on information in the generic link-layer header.
91  */
92 static void eth_fill_llh ( const struct ll_header *llhdr,
93                            struct pk_buff *pkb ) {
94         struct ethhdr *ethhdr = pkb->data;
95
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;
99 }
100
101 /**
102  * Parse Ethernet link-layer header
103  *
104  * @v pkb       Packet buffer
105  * @v llhdr     Generic link-layer header
106  *
107  * Fills in the generic link-layer header based on information in the
108  * Ethernet link-layer header in the packet buffer.
109  */
110 static void eth_parse_llh ( const struct pk_buff *pkb,
111                             struct ll_header *llhdr ) {
112         struct ethhdr *ethhdr = pkb->data;
113
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;
117
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;
122         } else {
123                 llhdr->dest_flags = 0;
124         }
125 }
126
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,
132         .route = eth_route,
133         .fill_llh = eth_fill_llh,
134         .parse_llh = eth_parse_llh,
135 };
136
137 LL_PROTOCOL ( ethernet_protocol );