/******************************************************************************
* 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
* *********************** 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)
*
* ************************************************************************
*
*/
/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
#include
#include
#include
#include
#include
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 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 < 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.
*
* 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);
}