summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
blob: bbfd6d1c3414365e124d818ee979caf9fb587109 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/******************************************************************************
 * 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 < 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);
}