Home | History | Annotate | Download | only in net
      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 = &ethernet_protocol;
    189 		netdev->ll_broadcast = eth_broadcast;
    190 		netdev->max_pkt_len = ETH_FRAME_LEN;
    191 	}
    192 	return netdev;
    193 }
    194