189 lines
5.4 KiB
C
189 lines
5.4 KiB
C
/******************************************************************************
|
|
* 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);
|
|
}
|