diff options
Diffstat (limited to 'roms/SLOF/lib/libnet/ethernet.c')
-rw-r--r-- | roms/SLOF/lib/libnet/ethernet.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/roms/SLOF/lib/libnet/ethernet.c b/roms/SLOF/lib/libnet/ethernet.c new file mode 100644 index 000000000..1e03a0bf3 --- /dev/null +++ b/roms/SLOF/lib/libnet/ethernet.c @@ -0,0 +1,189 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +/******************************* ALGORITHMS ******************************/ + +/** \file netbase.c <pre> + * *********************** Receive-handle diagram ************************* + * + * Note: Every layer calls out required upper layer + * + * lower + * | MAC/LLC Receive packet (receive_ether) + * | | + * | NETWORK +-----------+---------+ + * | | | + * | IPv4 (handle_ipv4) IPv6 (handle_ipv4) + * | ARP (handle_arp) ICMP & NDP + * | ICMP | + * | | | + * | +---------+---------+ + * | | + * | TRANSPORT +---------+---------+ + * | | | + * | TCP (handle_tcp) UDP (handle_udp) + * | | + * | APPLICATION +----------------+-----------+ + * V | | + * upper DNS (handle_dns) BootP / DHCP (handle_bootp_client) + * + * ************************************************************************ + * </pre> */ + + +/************************ DEFINITIONS & DECLARATIONS *********************/ + +#include <ethernet.h> +#include <string.h> +#include <sys/socket.h> +#include <ipv4.h> +#include <ipv6.h> + + +/****************************** LOCAL VARIABLES **************************/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static uint8_t own_mac[6] = {0, 0, 0, 0, 0, 0}; +static uint8_t multicast_mac[] = {0x01, 0x00, 0x5E}; +static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +/****************************** IMPLEMENTATION ***************************/ + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @param own_mac own hardware-address (MAC) + */ +void set_mac_address(const uint8_t * _own_mac) +{ + if (_own_mac) + memcpy(own_mac, _own_mac, 6); + else + memset(own_mac, 0, 6); +} + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @return own hardware-address (MAC) + */ +const uint8_t *get_mac_address(void) +{ + return own_mac; +} + +/** + * Ethernet: Check if given multicast address is a multicast MAC address + * starting with 0x3333 + * + * @return true or false + */ +static uint8_t is_multicast_mac(uint8_t * mac) +{ + + uint16_t mc = 0x3333; + if (memcmp(mac, &mc, 2) == 0) + return 1; + + return 0; +} + +/** + * Ethernet: Receives an ethernet-packet and handles it according to + * Receive-handle diagram. + * + * @param fd socket fd + * @return ZERO - packet was handled or no packets received; + * NON ZERO - error condition occurs. + */ +int32_t receive_ether(int fd) +{ + int32_t bytes_received; + struct ethhdr * ethh; + + memset(ether_packet, 0, ETH_MTU_SIZE); + bytes_received = recv(fd, ether_packet, ETH_MTU_SIZE, 0); + + if (!bytes_received) // No messages + return 0; + + if (bytes_received < 0) + return -1; /* recv() failed */ + + if ((size_t) bytes_received < sizeof(struct ethhdr)) + return -1; // packet is too small + + ethh = (struct ethhdr *) ether_packet; + + if(memcmp(ethh->dest_mac, broadcast_mac, 6) != 0 + && memcmp(ethh->dest_mac, multicast_mac, 3) != 0 + && memcmp(ethh->dest_mac, own_mac, 6 ) != 0 + && !is_multicast_mac(ethh->dest_mac)) + return -1; // packet is too small + + switch (htons(ethh -> type)) { + case ETHERTYPE_IP: + return handle_ipv4(fd, (uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); + + case ETHERTYPE_IPv6: + return handle_ipv6(fd, ether_packet + sizeof(struct ethhdr), + bytes_received - sizeof(struct ethhdr)); + + case ETHERTYPE_ARP: + return handle_arp(fd, (uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); + default: + break; + } + return -1; // unknown protocol +} + +/** + * Ethernet: Sends an ethernet frame via the initialized file descriptor. + * + * @return number of transmitted bytes + */ +int +send_ether(int fd, void* buffer, int len) +{ + return send(fd, buffer, len, 0); +} + +/** + * Ethernet: Creates Ethernet-packet. Places Ethernet-header in a packet and + * fills it with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_arphdr, fill_iphdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where eth-header must be placed. + * @param eth_type Type of the next level protocol (e.g. IP or ARP). + * @param src_mac Sender MAC address + * @param dest_mac Receiver MAC address + * @see ethhdr + * @see fill_arphdr + * @see fill_iphdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac) +{ + struct ethhdr * ethh = (struct ethhdr *) packet; + + ethh -> type = htons(eth_type); + memcpy(ethh -> src_mac, src_mac, 6); + memcpy(ethh -> dest_mac, dest_mac, 6); +} |