Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / 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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <byteswap.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <ipxe/if_arp.h>
30 #include <ipxe/if_ether.h>
31 #include <ipxe/in.h>
32 #include <ipxe/netdevice.h>
33 #include <ipxe/iobuf.h>
34 #include <ipxe/ethernet.h>
35
36 /** @file
37  *
38  * Ethernet protocol
39  *
40  */
41
42 /** Ethernet broadcast MAC address */
43 uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
44
45 /**
46  * Add Ethernet link-layer header
47  *
48  * @v netdev            Network device
49  * @v iobuf             I/O buffer
50  * @v ll_dest           Link-layer destination address
51  * @v ll_source         Source link-layer address
52  * @v net_proto         Network-layer protocol, in network-byte order
53  * @ret rc              Return status code
54  */
55 int eth_push ( struct net_device *netdev __unused, struct io_buffer *iobuf,
56                const void *ll_dest, const void *ll_source,
57                uint16_t net_proto ) {
58         struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
59
60         /* Build Ethernet header */
61         memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
62         memcpy ( ethhdr->h_source, ll_source, ETH_ALEN );
63         ethhdr->h_protocol = net_proto;
64
65         return 0;
66 }
67
68 /**
69  * Remove Ethernet link-layer header
70  *
71  * @v netdev            Network device
72  * @v iobuf             I/O buffer
73  * @ret ll_dest         Link-layer destination address
74  * @ret ll_source       Source link-layer address
75  * @ret net_proto       Network-layer protocol, in network-byte order
76  * @ret flags           Packet flags
77  * @ret rc              Return status code
78  */
79 int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
80                const void **ll_dest, const void **ll_source,
81                uint16_t *net_proto, unsigned int *flags ) {
82         struct ethhdr *ethhdr = iobuf->data;
83
84         /* Sanity check */
85         if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) {
86                 DBG ( "Ethernet packet too short (%zd bytes)\n",
87                       iob_len ( iobuf ) );
88                 return -EINVAL;
89         }
90
91         /* Strip off Ethernet header */
92         iob_pull ( iobuf, sizeof ( *ethhdr ) );
93
94         /* Fill in required fields */
95         *ll_dest = ethhdr->h_dest;
96         *ll_source = ethhdr->h_source;
97         *net_proto = ethhdr->h_protocol;
98         *flags = ( ( is_multicast_ether_addr ( ethhdr->h_dest ) ?
99                      LL_MULTICAST : 0 ) |
100                    ( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
101                      LL_BROADCAST : 0 ) );
102
103         return 0;
104 }
105
106 /**
107  * Initialise Ethernet address
108  *
109  * @v hw_addr           Hardware address
110  * @v ll_addr           Link-layer address
111  */
112 void eth_init_addr ( const void *hw_addr, void *ll_addr ) {
113         memcpy ( ll_addr, hw_addr, ETH_ALEN );
114 }
115
116 /**
117  * Generate random Ethernet address
118  *
119  * @v hw_addr           Generated hardware address
120  */
121 void eth_random_addr ( void *hw_addr ) {
122         uint8_t *addr = hw_addr;
123         unsigned int i;
124
125         for ( i = 0 ; i < ETH_ALEN ; i++ )
126                 addr[i] = random();
127         addr[0] &= ~0x01; /* Clear multicast bit */
128         addr[0] |= 0x02; /* Set locally-assigned bit */
129 }
130
131 /**
132  * Transcribe Ethernet address
133  *
134  * @v ll_addr           Link-layer address
135  * @ret string          Link-layer address in human-readable format
136  */
137 const char * eth_ntoa ( const void *ll_addr ) {
138         static char buf[18]; /* "00:00:00:00:00:00" */
139         const uint8_t *eth_addr = ll_addr;
140
141         sprintf ( buf, "%02x:%02x:%02x:%02x:%02x:%02x",
142                   eth_addr[0], eth_addr[1], eth_addr[2],
143                   eth_addr[3], eth_addr[4], eth_addr[5] );
144         return buf;
145 }
146
147 /**
148  * Hash multicast address
149  *
150  * @v af                Address family
151  * @v net_addr          Network-layer address
152  * @v ll_addr           Link-layer address to fill in
153  * @ret rc              Return status code
154  */
155 int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) {
156         const uint8_t *net_addr_bytes = net_addr;
157         uint8_t *ll_addr_bytes = ll_addr;
158
159         switch ( af ) {
160         case AF_INET:
161                 ll_addr_bytes[0] = 0x01;
162                 ll_addr_bytes[1] = 0x00;
163                 ll_addr_bytes[2] = 0x5e;
164                 ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f;
165                 ll_addr_bytes[4] = net_addr_bytes[2];
166                 ll_addr_bytes[5] = net_addr_bytes[3];
167                 return 0;
168         case AF_INET6:
169                 ll_addr_bytes[0] = 0x33;
170                 ll_addr_bytes[1] = 0x33;
171                 memcpy ( &ll_addr_bytes[2], &net_addr_bytes[12], 4 );
172                 return 0;
173         default:
174                 return -ENOTSUP;
175         }
176 }
177
178 /**
179  * Generate Ethernet-compatible compressed link-layer address
180  *
181  * @v ll_addr           Link-layer address
182  * @v eth_addr          Ethernet-compatible address to fill in
183  */
184 int eth_eth_addr ( const void *ll_addr, void *eth_addr ) {
185         memcpy ( eth_addr, ll_addr, ETH_ALEN );
186         return 0;
187 }
188
189 /**
190  * Generate EUI-64 address
191  *
192  * @v ll_addr           Link-layer address
193  * @v eui64             EUI-64 address to fill in
194  * @ret rc              Return status code
195  */
196 int eth_eui64 ( const void *ll_addr, void *eui64 ) {
197
198         memcpy ( ( eui64 + 0 ), ( ll_addr + 0 ), 3 );
199         memcpy ( ( eui64 + 5 ), ( ll_addr + 3 ), 3 );
200         *( ( uint16_t * ) ( eui64 + 3 ) ) = htons ( 0xfffe );
201         return 0;
202 }
203
204 /** Ethernet protocol */
205 struct ll_protocol ethernet_protocol __ll_protocol = {
206         .name           = "Ethernet",
207         .ll_proto       = htons ( ARPHRD_ETHER ),
208         .hw_addr_len    = ETH_ALEN,
209         .ll_addr_len    = ETH_ALEN,
210         .ll_header_len  = ETH_HLEN,
211         .push           = eth_push,
212         .pull           = eth_pull,
213         .init_addr      = eth_init_addr,
214         .ntoa           = eth_ntoa,
215         .mc_hash        = eth_mc_hash,
216         .eth_addr       = eth_eth_addr,
217         .eui64          = eth_eui64,
218 };
219
220 /**
221  * Allocate Ethernet device
222  *
223  * @v priv_size         Size of driver private data
224  * @ret netdev          Network device, or NULL
225  */
226 struct net_device * alloc_etherdev ( size_t priv_size ) {
227         struct net_device *netdev;
228
229         netdev = alloc_netdev ( priv_size );
230         if ( netdev ) {
231                 netdev->ll_protocol = &ethernet_protocol;
232                 netdev->ll_broadcast = eth_broadcast;
233                 netdev->max_pkt_len = ETH_FRAME_LEN;
234         }
235         return netdev;
236 }
237
238 /* Drag in Ethernet slow protocols */
239 REQUIRE_OBJECT ( eth_slow );