1 /* 2 * Copyright (C) 2006 Michael Brown <mbrown (at) 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 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <stdint.h> 22 #include <stdio.h> 23 #include <string.h> 24 #include <byteswap.h> 25 #include <errno.h> 26 #include <assert.h> 27 #include <gpxe/if_arp.h> 28 #include <gpxe/if_ether.h> 29 #include <gpxe/in.h> 30 #include <gpxe/netdevice.h> 31 #include <gpxe/iobuf.h> 32 #include <gpxe/ethernet.h> 33 34 /** @file 35 * 36 * Ethernet protocol 37 * 38 */ 39 40 /** Ethernet broadcast MAC address */ 41 static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 42 43 /** 44 * Add Ethernet link-layer header 45 * 46 * @v netdev Network device 47 * @v iobuf I/O buffer 48 * @v ll_dest Link-layer destination address 49 * @v ll_source Source link-layer address 50 * @v net_proto Network-layer protocol, in network-byte order 51 * @ret rc Return status code 52 */ 53 static int eth_push ( struct net_device *netdev __unused, 54 struct io_buffer *iobuf, const void *ll_dest, 55 const void *ll_source, uint16_t net_proto ) { 56 struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) ); 57 58 /* Build Ethernet header */ 59 memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN ); 60 memcpy ( ethhdr->h_source, ll_source, ETH_ALEN ); 61 ethhdr->h_protocol = net_proto; 62 63 return 0; 64 } 65 66 /** 67 * Remove Ethernet link-layer header 68 * 69 * @v netdev Network device 70 * @v iobuf I/O buffer 71 * @ret ll_dest Link-layer destination address 72 * @ret ll_source Source link-layer address 73 * @ret net_proto Network-layer protocol, in network-byte order 74 * @ret rc Return status code 75 */ 76 static int eth_pull ( struct net_device *netdev __unused, 77 struct io_buffer *iobuf, const void **ll_dest, 78 const void **ll_source, uint16_t *net_proto ) { 79 struct ethhdr *ethhdr = iobuf->data; 80 81 /* Sanity check */ 82 if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) { 83 DBG ( "Ethernet packet too short (%zd bytes)\n", 84 iob_len ( iobuf ) ); 85 return -EINVAL; 86 } 87 88 /* Strip off Ethernet header */ 89 iob_pull ( iobuf, sizeof ( *ethhdr ) ); 90 91 /* Fill in required fields */ 92 *ll_dest = ethhdr->h_dest; 93 *ll_source = ethhdr->h_source; 94 *net_proto = ethhdr->h_protocol; 95 96 return 0; 97 } 98 99 /** 100 * Initialise Ethernet address 101 * 102 * @v hw_addr Hardware address 103 * @v ll_addr Link-layer address 104 */ 105 void eth_init_addr ( const void *hw_addr, void *ll_addr ) { 106 memcpy ( ll_addr, hw_addr, ETH_ALEN ); 107 } 108 109 /** 110 * Transcribe Ethernet address 111 * 112 * @v ll_addr Link-layer address 113 * @ret string Link-layer address in human-readable format 114 */ 115 const char * eth_ntoa ( const void *ll_addr ) { 116 static char buf[18]; /* "00:00:00:00:00:00" */ 117 const uint8_t *eth_addr = ll_addr; 118 119 sprintf ( buf, "%02x:%02x:%02x:%02x:%02x:%02x", 120 eth_addr[0], eth_addr[1], eth_addr[2], 121 eth_addr[3], eth_addr[4], eth_addr[5] ); 122 return buf; 123 } 124 125 /** 126 * Hash multicast address 127 * 128 * @v af Address family 129 * @v net_addr Network-layer address 130 * @v ll_addr Link-layer address to fill in 131 * @ret rc Return status code 132 */ 133 int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) { 134 const uint8_t *net_addr_bytes = net_addr; 135 uint8_t *ll_addr_bytes = ll_addr; 136 137 switch ( af ) { 138 case AF_INET: 139 ll_addr_bytes[0] = 0x01; 140 ll_addr_bytes[1] = 0x00; 141 ll_addr_bytes[2] = 0x5e; 142 ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f; 143 ll_addr_bytes[4] = net_addr_bytes[2]; 144 ll_addr_bytes[5] = net_addr_bytes[3]; 145 return 0; 146 default: 147 return -ENOTSUP; 148 } 149 } 150 151 /** 152 * Generate Ethernet-compatible compressed link-layer address 153 * 154 * @v ll_addr Link-layer address 155 * @v eth_addr Ethernet-compatible address to fill in 156 */ 157 int eth_eth_addr ( const void *ll_addr, void *eth_addr ) { 158 memcpy ( eth_addr, ll_addr, ETH_ALEN ); 159 return 0; 160 } 161 162 /** Ethernet protocol */ 163 struct ll_protocol ethernet_protocol __ll_protocol = { 164 .name = "Ethernet", 165 .ll_proto = htons ( ARPHRD_ETHER ), 166 .hw_addr_len = ETH_ALEN, 167 .ll_addr_len = ETH_ALEN, 168 .ll_header_len = ETH_HLEN, 169 .push = eth_push, 170 .pull = eth_pull, 171 .init_addr = eth_init_addr, 172 .ntoa = eth_ntoa, 173 .mc_hash = eth_mc_hash, 174 .eth_addr = eth_eth_addr, 175 }; 176 177 /** 178 * Allocate Ethernet device 179 * 180 * @v priv_size Size of driver private data 181 * @ret netdev Network device, or NULL 182 */ 183 struct net_device * alloc_etherdev ( size_t priv_size ) { 184 struct net_device *netdev; 185 186 netdev = alloc_netdev ( priv_size ); 187 if ( netdev ) { 188 netdev->ll_protocol = ðernet_protocol; 189 netdev->ll_broadcast = eth_broadcast; 190 netdev->max_pkt_len = ETH_FRAME_LEN; 191 } 192 return netdev; 193 } 194