~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/net/ethernet.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
26
#include <stdint.h>
 
27
#include <stdlib.h>
 
28
#include <stdio.h>
 
29
#include <string.h>
 
30
#include <byteswap.h>
 
31
#include <errno.h>
 
32
#include <assert.h>
 
33
#include <ipxe/if_arp.h>
 
34
#include <ipxe/if_ether.h>
 
35
#include <ipxe/in.h>
 
36
#include <ipxe/netdevice.h>
 
37
#include <ipxe/iobuf.h>
 
38
#include <ipxe/ethernet.h>
 
39
 
 
40
/** @file
 
41
 *
 
42
 * Ethernet protocol
 
43
 *
 
44
 */
 
45
 
 
46
/** Ethernet broadcast MAC address */
 
47
uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
48
 
 
49
/**
 
50
 * Check if Ethernet packet has an 802.3 LLC header
 
51
 *
 
52
 * @v ethhdr            Ethernet header
 
53
 * @ret is_llc          Packet has 802.3 LLC header
 
54
 */
 
55
static inline int eth_is_llc_packet ( struct ethhdr *ethhdr ) {
 
56
        uint8_t len_msb;
 
57
 
 
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
 
61
         * instruction.
 
62
         */
 
63
        len_msb = *( ( uint8_t * ) &ethhdr->h_protocol );
 
64
        return ( len_msb < 0x06 );
 
65
}
 
66
 
 
67
/**
 
68
 * Add Ethernet link-layer header
 
69
 *
 
70
 * @v netdev            Network device
 
71
 * @v iobuf             I/O buffer
 
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
 
76
 */
 
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 ) );
 
81
 
 
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;
 
86
 
 
87
        return 0;
 
88
}
 
89
 
 
90
/**
 
91
 * Remove Ethernet link-layer header
 
92
 *
 
93
 * @v netdev            Network device
 
94
 * @v iobuf             I/O buffer
 
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
 
100
 */
 
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;
 
105
        uint16_t *llc_proto;
 
106
 
 
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.
 
111
         */
 
112
        if ( iob_len ( iobuf ) < ( sizeof ( *ethhdr ) + sizeof ( *llc_proto ))){
 
113
                DBG ( "Ethernet packet too short (%zd bytes)\n",
 
114
                      iob_len ( iobuf ) );
 
115
                return -EINVAL;
 
116
        }
 
117
 
 
118
        /* Strip off Ethernet header */
 
119
        iob_pull ( iobuf, sizeof ( *ethhdr ) );
 
120
 
 
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 ) ?
 
126
                     LL_MULTICAST : 0 ) |
 
127
                   ( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
 
128
                     LL_BROADCAST : 0 ) );
 
129
 
 
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.
 
135
         */
 
136
        if ( eth_is_llc_packet ( ethhdr ) ) {
 
137
                llc_proto = ( &ethhdr->h_protocol + 1 );
 
138
                *net_proto = *llc_proto;
 
139
        }
 
140
 
 
141
        return 0;
 
142
}
 
143
 
 
144
/**
 
145
 * Initialise Ethernet address
 
146
 *
 
147
 * @v hw_addr           Hardware address
 
148
 * @v ll_addr           Link-layer address
 
149
 */
 
150
void eth_init_addr ( const void *hw_addr, void *ll_addr ) {
 
151
        memcpy ( ll_addr, hw_addr, ETH_ALEN );
 
152
}
 
153
 
 
154
/**
 
155
 * Generate random Ethernet address
 
156
 *
 
157
 * @v hw_addr           Generated hardware address
 
158
 */
 
159
void eth_random_addr ( void *hw_addr ) {
 
160
        uint8_t *addr = hw_addr;
 
161
        unsigned int i;
 
162
 
 
163
        for ( i = 0 ; i < ETH_ALEN ; i++ )
 
164
                addr[i] = random();
 
165
        addr[0] &= ~0x01; /* Clear multicast bit */
 
166
        addr[0] |= 0x02; /* Set locally-assigned bit */
 
167
}
 
168
 
 
169
/**
 
170
 * Transcribe Ethernet address
 
171
 *
 
172
 * @v ll_addr           Link-layer address
 
173
 * @ret string          Link-layer address in human-readable format
 
174
 */
 
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;
 
178
 
 
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] );
 
182
        return buf;
 
183
}
 
184
 
 
185
/**
 
186
 * Hash multicast address
 
187
 *
 
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
 
192
 */
 
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;
 
196
 
 
197
        switch ( af ) {
 
198
        case AF_INET:
 
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];
 
205
                return 0;
 
206
        case AF_INET6:
 
207
                ll_addr_bytes[0] = 0x33;
 
208
                ll_addr_bytes[1] = 0x33;
 
209
                memcpy ( &ll_addr_bytes[2], &net_addr_bytes[12], 4 );
 
210
                return 0;
 
211
        default:
 
212
                return -ENOTSUP;
 
213
        }
 
214
}
 
215
 
 
216
/**
 
217
 * Generate Ethernet-compatible compressed link-layer address
 
218
 *
 
219
 * @v ll_addr           Link-layer address
 
220
 * @v eth_addr          Ethernet-compatible address to fill in
 
221
 */
 
222
int eth_eth_addr ( const void *ll_addr, void *eth_addr ) {
 
223
        memcpy ( eth_addr, ll_addr, ETH_ALEN );
 
224
        return 0;
 
225
}
 
226
 
 
227
/**
 
228
 * Generate EUI-64 address
 
229
 *
 
230
 * @v ll_addr           Link-layer address
 
231
 * @v eui64             EUI-64 address to fill in
 
232
 * @ret rc              Return status code
 
233
 */
 
234
int eth_eui64 ( const void *ll_addr, void *eui64 ) {
 
235
 
 
236
        memcpy ( ( eui64 + 0 ), ( ll_addr + 0 ), 3 );
 
237
        memcpy ( ( eui64 + 5 ), ( ll_addr + 3 ), 3 );
 
238
        *( ( uint16_t * ) ( eui64 + 3 ) ) = htons ( 0xfffe );
 
239
        return 0;
 
240
}
 
241
 
 
242
/** Ethernet protocol */
 
243
struct ll_protocol ethernet_protocol __ll_protocol = {
 
244
        .name           = "Ethernet",
 
245
        .ll_proto       = htons ( ARPHRD_ETHER ),
 
246
        .hw_addr_len    = ETH_ALEN,
 
247
        .ll_addr_len    = ETH_ALEN,
 
248
        .ll_header_len  = ETH_HLEN,
 
249
        .push           = eth_push,
 
250
        .pull           = eth_pull,
 
251
        .init_addr      = eth_init_addr,
 
252
        .ntoa           = eth_ntoa,
 
253
        .mc_hash        = eth_mc_hash,
 
254
        .eth_addr       = eth_eth_addr,
 
255
        .eui64          = eth_eui64,
 
256
};
 
257
 
 
258
/**
 
259
 * Allocate Ethernet device
 
260
 *
 
261
 * @v priv_size         Size of driver private data
 
262
 * @ret netdev          Network device, or NULL
 
263
 */
 
264
struct net_device * alloc_etherdev ( size_t priv_size ) {
 
265
        struct net_device *netdev;
 
266
 
 
267
        netdev = alloc_netdev ( priv_size );
 
268
        if ( netdev ) {
 
269
                netdev->ll_protocol = &ethernet_protocol;
 
270
                netdev->ll_broadcast = eth_broadcast;
 
271
                netdev->max_pkt_len = ETH_FRAME_LEN;
 
272
        }
 
273
        return netdev;
 
274
}
 
275
 
 
276
/* Drag in objects via ethernet_protocol */
 
277
REQUIRING_SYMBOL ( ethernet_protocol );
 
278
 
 
279
/* Drag in Ethernet configuration */
 
280
REQUIRE_OBJECT ( config_ethernet );