summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/clients/net-snk/app/netlib
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/SLOF/clients/net-snk/app/netlib')
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/Makefile42
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c254
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c998
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h53
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c216
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h157
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c527
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h28
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c187
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.h47
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c391
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.h135
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c904
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h96
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c768
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h196
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c147
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h70
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c50
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.h27
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c597
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.h51
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c151
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h58
24 files changed, 6150 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/Makefile b/qemu/roms/SLOF/clients/net-snk/app/netlib/Makefile
new file mode 100644
index 000000000..df09bf82e
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/Makefile
@@ -0,0 +1,42 @@
+# *****************************************************************************
+# * 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
+# ****************************************************************************/
+
+ifndef TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS += -I../
+
+ifeq ($(SNK_USE_MTFTP), 1)
+CFLAGS += -DUSE_MTFTP
+endif
+
+OBJS = ethernet.o ipv4.o udp.o tcp.o dns.o bootp.o \
+ dhcp.o ipv6.o dhcpv6.o icmpv6.o ndp.o
+
+ifeq ($(SNK_USE_MTFTP), 1)
+OBJS += mtftp.o
+else
+OBJS += tftp.o
+endif
+
+all: netlib.o
+
+netlib.o: $(OBJS)
+ $(LD) $(LDFLAGS) $^ -o $@ -r
+
+clean:
+ $(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c
new file mode 100644
index 000000000..1bc6efe5b
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c
@@ -0,0 +1,254 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#include <ethernet.h>
+#include <ipv4.h>
+#include <udp.h>
+#include <dhcp.h>
+
+#define DEBUG 0
+
+static char * response_buffer;
+
+#if DEBUG
+static void
+print_ip(char *ip)
+{
+ printf("%d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
+}
+#endif
+
+/* IP header checksum calculation */
+static unsigned short
+checksum(unsigned short *packet, int words)
+{
+ unsigned long checksum;
+ for (checksum = 0; words > 0; words--)
+ checksum += *packet++;
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+ return ~checksum;
+}
+
+
+static int
+send_bootp(filename_ip_t * fn_ip)
+{
+#if DEBUG
+ int i;
+#endif
+ unsigned int packetsize =
+ sizeof(struct iphdr) + sizeof(struct ethhdr) +
+ sizeof(struct udphdr) + sizeof(struct btphdr);
+ unsigned char packet[packetsize];
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct btphdr *btph;
+
+ iph = (struct iphdr *) packet;
+ udph = (struct udphdr *) (iph + 1);
+ btph = (struct btphdr *) (udph + 1);
+
+ memset(packet, 0, packetsize);
+
+ fill_iphdr((uint8_t *) iph, htons(packetsize - sizeof(struct ethhdr)),
+ IPTYPE_UDP, 0, fn_ip->server_ip);
+ fill_udphdr((uint8_t *) udph,
+ htons(sizeof(struct udphdr) + sizeof(struct btphdr)),
+ htons(UDPPORT_BOOTPC), htons(UDPPORT_BOOTPS));
+ btph->op = 1;
+ btph->htype = 1;
+ btph->hlen = 6;
+ strcpy((char *) btph->file, "bla");
+ memcpy(btph->chaddr, get_mac_address(), 6);
+
+#if DEBUG
+ printf("Sending packet\n");
+ printf("Packet is ");
+ for (i = 0; i < packetsize; i++)
+ printf(" %02x", packet[i]);
+ printf(".\n");
+#endif
+
+ send_ipv4(fn_ip->fd, packet, iph->ip_len);
+#if DEBUG
+ printf("%d bytes transmitted over socket.\n", i);
+#endif
+
+ return 0;
+}
+
+
+static int
+receive_bootp(filename_ip_t * fn_ip)
+{
+ int len, old_sum;
+ unsigned int packetsize = 2000;
+ unsigned char packet[packetsize];
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct btphdr *btph;
+
+#if DEBUG
+ struct ethhdr *ethh;
+ ethh = (struct ethhdr *) packet;
+#endif
+
+ iph = (struct iphdr *) (packet + sizeof(struct ethhdr));
+ udph = (struct udphdr *) (iph + 1);
+ btph = (struct btphdr *) (udph + 1);
+
+ memset(packet, 0, packetsize);
+
+ /* setting up a timer with a timeout of one second */
+ set_timer(TICKS_SEC);
+
+ do {
+
+ /* let's receive a packet */
+ len = recv(fn_ip->fd, packet, packetsize, 0);
+
+#if DEBUG
+ int j;
+ printf("%d bytes received, %d expected \n", len, packetsize);
+ if (len == 346) {
+ printf("Rec packet\n");
+ printf("Packet is ");
+ for (j = 0; j < len; j++) {
+ if (j % 16 == 0)
+ printf("\n");
+ printf(" %02x", packet[j]);
+ }
+ printf(".\n");
+ }
+#endif
+ if (len == 0)
+ continue;
+
+ /* check if the ip checksum is correct */
+ old_sum = iph->ip_sum;
+ iph->ip_sum = 0x00;
+ if (old_sum !=
+ checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1))
+ /* checksum failed */
+ continue;
+ /* is it a udp packet */
+ if (iph->ip_p != IPTYPE_UDP)
+ continue;
+ /* check if the source port and destination port and the packet
+ * say that it is a bootp answer */
+ if (udph->uh_dport != htons(UDPPORT_BOOTPC) || udph->uh_sport != htons(UDPPORT_BOOTPS))
+ continue;
+ /* check if it is a Boot Reply */
+ if (btph->op != 2)
+ continue;
+ /* Comparing our mac address with the one in the bootp reply */
+ if (memcmp(get_mac_address(), btph->chaddr, ETH_ALEN))
+ continue;
+
+ if(response_buffer)
+ memcpy(response_buffer, btph, 1720);
+
+ fn_ip->own_ip = btph->yiaddr;
+ fn_ip->server_ip = btph->siaddr;
+ strcpy((char *) fn_ip->filename, (char *) btph->file);
+
+#if DEBUG
+ printf("\nThese are the details of the bootp reply:\n");
+ printf("Our IP address: ");
+ print_ip((char*) &fn_ip->own_ip);
+ printf("Next server IP address: ");
+ print_ip((char*) &fn_ip->server_ip);
+ printf("Boot file name: %s\n", btph->file);
+ printf("Packet is: %s\n", btph->file);
+ for (j = 0; j < len; j++) {
+ if (j % 16 == 0)
+ printf("\n");
+ printf(" %02x", packet[j]);
+ }
+ printf(".\n");
+ printf("fn_ip->own_mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_mac_address()[0], get_mac_address()[1],
+ get_mac_address()[2], get_mac_address()[3],
+ get_mac_address()[4], get_mac_address()[5]);
+ printf("Header ethh->dest_mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ethh->dest_mac[0], ethh->dest_mac[1], ethh->dest_mac[2],
+ ethh->dest_mac[3], ethh->dest_mac[4], ethh->dest_mac[5]);
+ printf("Header ethh->src_mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ethh->src_mac[0], ethh->src_mac[1], ethh->src_mac[2],
+ ethh->src_mac[3], ethh->src_mac[4], ethh->src_mac[5]);
+ printf("Header ethh->typ: %x\n",ethh->type);
+ printf("Header iph->ip_hlv: %x\n",iph->ip_hlv);
+ printf("Header iph->ip_len: %x\n",iph->ip_len);
+ printf("Header iph->ip_id: %x\n",iph->ip_id);
+ printf("Header iph->ip_off: %x\n",iph->ip_off);
+ printf("Header iph->ip_ttl: %x\n",iph->ip_ttl);
+ printf("Header iph->ip_p: %x\n",iph->ip_p);
+ printf("Header iph->ip_sum: %x\n",iph->ip_sum);
+ printf("Header iph->ip_src: %x\n",iph->ip_src);
+ printf("Header iph->ip_dst: %x\n",iph->ip_dst);
+
+ printf("Header btph->op: %x\n",btph->op);
+ printf("Header btph->htype: %x\n",btph->htype);
+ printf("Header btph->hlen: %x\n",btph->hlen);
+ printf("Header btph->hops: %x\n",btph->hops);
+ printf("Header btph->xid: %x\n",btph->xid);
+ printf("Header btph->secs: %x\n",btph->secs);
+ printf("Header btph->ciaddr: %x\n",btph->ciaddr);
+ printf("Header btph->yiaddr: %x\n",btph->yiaddr);
+ printf("Header btph->siaddr: %x\n",btph->siaddr);
+ printf("Header btph->giaddr: %x\n",btph->giaddr);
+
+ printf("Header btph->chaddr: %02x:%02x:%02x:%02x:%02x:%02x:\n",
+ btph->chaddr[0], btph->chaddr[1], btph->chaddr[2],
+ btph->chaddr[3], btph->chaddr[4], btph->chaddr[5]);
+#endif
+ return 0;
+
+ /* only do this for the time specified during set_timer() */
+ } while (get_timer() > 0);
+ return -1;
+}
+
+
+int
+bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries)
+{
+ int i = (int) retries+1;
+ fn_ip->own_ip = 0;
+
+ printf(" ");
+
+ response_buffer = ret_buffer;
+
+ do {
+ printf("\b\b%02d", i);
+ if (!i--) {
+ printf("\nGiving up after %d bootp requests\n",
+ retries+1);
+ return -1;
+ }
+ send_bootp(fn_ip);
+ /* if the timer in receive_bootp expired it will return
+ * -1 and we will just send another bootp request just
+ * in case the previous one was lost. And because we don't
+ * trust the network cable we keep on doing this 30 times */
+ } while (receive_bootp(fn_ip) != 0);
+ printf("\b\b\b");
+ return 0;
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c
new file mode 100644
index 000000000..5f26f3afb
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c
@@ -0,0 +1,998 @@
+/******************************************************************************
+ * 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 dhcp.c <pre>
+ * **************** State-transition diagram for DHCP client *************
+ *
+ * +---------+ Note: DHCP-server msg / DHCP-client msg
+ * | INIT |
+ * +---------+
+ * |
+ * | - / Discover
+ * V
+ * +---------+
+ * | SELECT | Timeout
+ * +---------+ |
+ * | |
+ * | Offer / Request |
+ * | |
+ * V V
+ * +---------+ NACK / - ***********
+ * | REQUEST | ----------------> * FAULT *
+ * +---------+ ***********
+ * |
+ * | ACK / - ***********
+ * +----------------------> * SUCCESS *
+ * ***********
+ *
+ * ************************************************************************
+ * </pre> */
+
+
+/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+
+#include <dhcp.h>
+#include <ethernet.h>
+#include <ipv4.h>
+#include <udp.h>
+#include <dns.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/* DHCP Message Types */
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNACK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+
+/* DHCP Option Codes */
+#define DHCP_MASK 1
+#define DHCP_ROUTER 3
+#define DHCP_DNS 6
+#define DHCP_REQUESTED_IP 50
+#define DHCP_OVERLOAD 52
+#define DHCP_MSG_TYPE 53
+#define DHCP_SERVER_ID 54
+#define DHCP_REQUEST_LIST 55
+#define DHCP_TFTP_SERVER 66
+#define DHCP_BOOTFILE 67
+#define DHCP_CLIENT_ARCH 93
+#define DHCP_ENDOPT 0xFF
+#define DHCP_PADOPT 0x00
+
+/* "file/sname" overload option values */
+#define DHCP_OVERLOAD_FILE 1
+#define DHCP_OVERLOAD_SNAME 2
+#define DHCP_OVERLOAD_BOTH 3
+
+/* DHCP states codes */
+#define DHCP_STATE_SELECT 1
+#define DHCP_STATE_REQUEST 2
+#define DHCP_STATE_SUCCESS 3
+#define DHCP_STATE_FAULT 4
+
+/* DHCP Client Architecture */
+#ifndef DHCPARCH
+#define USE_DHCPARCH 0
+#define DHCPARCH 0
+#else
+#define USE_DHCPARCH 1
+#endif
+
+static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
+/**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */
+
+/** \struct dhcp_options_t
+ * This structure is used to fill options in DHCP-msg during transmitting
+ * or to retrieve options from DHCP-msg during receiving.
+ * <p>
+ * If flag[i] == TRUE then field for i-th option retains valid value and
+ * information from this field may retrived (in case of receiving) or will
+ * be transmitted (in case of transmitting).
+ *
+ */
+typedef struct {
+ uint8_t flag[256]; /**< Show if corresponding opt. is valid */
+ uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th
+ option will be requested from server */
+ uint32_t server_ID; /**< o.54 Identifies DHCP-server */
+ uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */
+ uint32_t dns_IP; /**< o. 6 DNS IP */
+ uint32_t router_IP; /**< o. 3 Router IP */
+ uint32_t subnet_mask; /**< o. 1 Subnet mask */
+ uint8_t msg_type; /**< o.53 DHCP-message type */
+ uint8_t overload; /**< o.52 Overload sname/file fields */
+ int8_t tftp_server[256]; /**< o.66 TFTP server name */
+ int8_t bootfile[256]; /**< o.67 Boot file name */
+ uint16_t client_arch; /**< o.93 Client architecture type */
+} dhcp_options_t;
+
+/** Stores state of DHCP-client (refer to State-transition diagram) */
+static uint8_t dhcp_state;
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static int32_t
+dhcp_attempt(int fd);
+
+static int32_t
+dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
+
+static int32_t
+dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+ dhcp_options_t * opt_struct);
+
+static int8_t
+dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t src_options[], uint32_t src_len);
+
+static int8_t
+dhcp_find_option(uint8_t options[], uint32_t len,
+ uint8_t op_code, uint32_t * op_offset);
+
+static void
+dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t * new_option);
+
+static void
+dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint32_t dst_offset, uint8_t * new_option);
+
+static void
+dhcp_send_discover(int fd);
+
+static void
+dhcp_send_request(int fd);
+
+static uint8_t
+strtoip(int8_t * str, uint32_t * ip);
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static uint8_t ether_packet[ETH_MTU_SIZE];
+static uint32_t dhcp_own_ip = 0;
+static uint32_t dhcp_server_ip = 0;
+static uint32_t dhcp_siaddr_ip = 0;
+static int8_t dhcp_filename[256];
+static int8_t dhcp_tftp_name[256];
+
+static char * response_buffer;
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+int32_t
+dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) {
+
+ uint32_t dhcp_tftp_ip = 0;
+ int fd = fn_ip->fd;
+
+ strcpy((char *) dhcp_filename, "");
+ strcpy((char *) dhcp_tftp_name, "");
+
+ response_buffer = ret_buffer;
+
+ if (dhcp_attempt(fd) == 0)
+ return -1;
+
+ if (fn_ip->own_ip) {
+ dhcp_own_ip = fn_ip->own_ip;
+ }
+ if (fn_ip->server_ip) {
+ dhcp_siaddr_ip = fn_ip->server_ip;
+ }
+ if(fn_ip->filename[0] != 0) {
+ strcpy((char *) dhcp_filename, (char *) fn_ip->filename);
+ }
+
+ // TFTP SERVER
+ if (!strlen((char *) dhcp_tftp_name)) {
+ if (!dhcp_siaddr_ip) {
+ // ERROR: TFTP name is not presented
+ return -3;
+ }
+
+ // take TFTP-ip from siaddr field
+ dhcp_tftp_ip = dhcp_siaddr_ip;
+ }
+ else {
+ // TFTP server defined by its name
+ if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
+ if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&(dhcp_tftp_ip), 4)) {
+ // DNS error - can't obtain TFTP-server name
+ // Use TFTP-ip from siaddr field, if presented
+ if (dhcp_siaddr_ip) {
+ dhcp_tftp_ip = dhcp_siaddr_ip;
+ }
+ else {
+ // ERROR: Can't obtain TFTP server IP
+ return -4;
+ }
+ }
+ }
+ }
+
+ // Store configuration info into filename_ip strucutre
+ fn_ip -> own_ip = dhcp_own_ip;
+ fn_ip -> server_ip = dhcp_tftp_ip;
+ strcpy((char *) fn_ip -> filename, (char *) dhcp_filename);
+
+ return 0;
+}
+
+/**
+ * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
+ */
+static int32_t
+dhcp_attempt(int fd) {
+ int sec;
+
+ // Send DISCOVER message and switch DHCP-client to SELECT state
+ dhcp_send_discover(fd);
+
+ dhcp_state = DHCP_STATE_SELECT;
+
+ // setting up a timer with a timeout of two seconds
+ for (sec = 0; sec < 2; sec++) {
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether(fd);
+
+ // Wait until client will switch to Final state or Timeout occurs
+ switch (dhcp_state) {
+ case DHCP_STATE_SUCCESS :
+ return 1;
+ case DHCP_STATE_FAULT :
+ return 0;
+ }
+ } while (get_timer() > 0);
+ }
+
+ // timeout
+ return 0;
+}
+
+/**
+ * DHCP: Supplements DHCP-message with options stored in structure.
+ * For more information about option coding see dhcp_options_t.
+ *
+ * @param opt_field Points to the "vend" field of DHCP-message
+ * (destination)
+ * @param opt_struct this structure stores info about the options which
+ * will be added to DHCP-message (source)
+ * @return TRUE - options packed;
+ * FALSE - error condition occurs.
+ * @see dhcp_options_t
+ */
+static int32_t
+dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
+ uint8_t * options = opt_field;
+ uint16_t i, sum; // used to define is any options set
+
+ // magic
+ memcpy(options, dhcp_magic, 4);
+ options += 4;
+
+ // fill message type
+ switch (opt_struct -> msg_type) {
+ case DHCPDISCOVER :
+ case DHCPREQUEST :
+ case DHCPDECLINE :
+ case DHCPINFORM :
+ case DHCPRELEASE :
+ options[0] = DHCP_MSG_TYPE;
+ options[1] = 1;
+ options[2] = opt_struct -> msg_type;
+ options += 3;
+ break;
+ default :
+ return 0; // Unsupported DHCP-message
+ }
+
+ if (opt_struct -> overload) {
+ options[0] = DHCP_OVERLOAD;
+ options[1] = 0x01;
+ options[2] = opt_struct -> overload;
+ options +=3;
+ }
+
+ if (opt_struct -> flag[DHCP_REQUESTED_IP]) {
+ options[0] = DHCP_REQUESTED_IP;
+ options[1] = 0x04;
+ * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP);
+ options +=6;
+ }
+
+ if (opt_struct -> flag[DHCP_SERVER_ID]) {
+ options[0] = DHCP_SERVER_ID;
+ options[1] = 0x04;
+ * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID);
+ options +=6;
+ }
+
+ sum = 0;
+ for (i = 0; i < 256; i++)
+ sum += opt_struct -> request_list[i];
+
+ if (sum) {
+ options[0] = DHCP_REQUEST_LIST;
+ options[1] = sum;
+ options += 2;
+ for (i = 0; i < 256; i++) {
+ if (opt_struct -> request_list[i]) {
+ options[0] = i; options++;
+ }
+ }
+ }
+
+ if (opt_struct -> flag[DHCP_TFTP_SERVER]) {
+ options[0] = DHCP_TFTP_SERVER;
+ options[1] = strlen((char *) opt_struct -> tftp_server) + 1;
+ memcpy(options + 2, opt_struct -> tftp_server, options[1]);
+ options += options[1] + 2;
+ }
+
+ if (opt_struct -> flag[DHCP_BOOTFILE]) {
+ options[0] = DHCP_BOOTFILE;
+ options[1] = strlen((char *) opt_struct -> bootfile) + 1;
+ memcpy(options + 2, opt_struct -> bootfile, options[1]);
+ options += options[1] + 2;
+ }
+
+ if (opt_struct -> flag[DHCP_CLIENT_ARCH]) {
+ options[0] = DHCP_CLIENT_ARCH;
+ options[1] = 2;
+ options[2] = (DHCPARCH >> 8);
+ options[3] = DHCPARCH & 0xff;
+ options += 4;
+ }
+
+ // end options
+ options[0] = 0xFF;
+ options++;
+
+ return 1;
+}
+
+/**
+ * DHCP: Extracts encoded options from DHCP-message into the structure.
+ * For more information about option coding see dhcp_options_t.
+ *
+ * @param opt_field Points to the "options" field of DHCP-message
+ * (source).
+ * @param opt_len Length of "options" field.
+ * @param opt_struct this structure stores info about the options which
+ * was extracted from DHCP-message (destination).
+ * @return TRUE - options extracted;
+ * FALSE - error condition occurs.
+ * @see dhcp_options_t
+ */
+static int32_t
+dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+ dhcp_options_t * opt_struct) {
+ int32_t offset = 0;
+
+ memset(opt_struct, 0, sizeof(dhcp_options_t));
+
+ // magic
+ if (memcmp(opt_field, dhcp_magic, 4)) {
+ return 0;
+ }
+
+ offset += 4;
+ while (offset < opt_len) {
+ opt_struct -> flag[opt_field[offset]] = 1;
+ switch(opt_field[offset]) {
+ case DHCP_OVERLOAD :
+ opt_struct -> overload = opt_field[offset + 2];
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_REQUESTED_IP :
+ opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_MASK :
+ opt_struct -> flag[DHCP_MASK] = 1;
+ opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_DNS :
+ opt_struct -> flag[DHCP_DNS] = 1;
+ opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_ROUTER :
+ opt_struct -> flag[DHCP_ROUTER] = 1;
+ opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_MSG_TYPE :
+ if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9))
+ opt_struct -> msg_type = opt_field[offset + 2];
+ else
+ return 0;
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_SERVER_ID :
+ opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_TFTP_SERVER :
+ memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]);
+ (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0;
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_BOOTFILE :
+ memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offset + 1]);
+ (opt_struct -> bootfile)[opt_field[offset + 1]] = 0;
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_CLIENT_ARCH :
+ opt_struct -> client_arch = ((opt_field[offset + 2] << 8) & 0xFF00) | (opt_field[offset + 3] & 0xFF);
+ offset += 4;
+ break;
+
+ case DHCP_PADOPT :
+ offset++;
+ break;
+
+ case DHCP_ENDOPT : // End of options
+ return 1;
+
+ default :
+ offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing
+ }
+ }
+ if (offset == opt_len)
+ return 1; // options finished without 0xFF
+
+ return 0;
+}
+
+/**
+ * DHCP: Appends information from source "options" into dest "options".
+ * This function is used to support "file/sname" overloading.
+ *
+ * @param dst_options destanation "options" field
+ * @param dst_len size of dst_options (modified by this function)
+ * @param src_options source "options" field
+ * @param src_len size of src_options
+ * @return TRUE - options merged;
+ * FALSE - error condition occurs.
+ */
+static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t src_options[], uint32_t src_len) {
+ int32_t dst_offset, src_offset = 0;
+
+ // remove ENDOPT if presented
+ if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset))
+ * dst_len = dst_offset;
+
+ while (src_offset < src_len) {
+ switch(src_options[src_offset]) {
+ case DHCP_PADOPT:
+ src_offset++;
+ break;
+ case DHCP_ENDOPT:
+ return 1;
+ default:
+ if (dhcp_find_option(dst_options, * dst_len,
+ src_options[src_offset],
+ (uint32_t *) &dst_offset)) {
+ dhcp_combine_option(dst_options, dst_len,
+ dst_offset,
+ (uint8_t *) src_options +
+ src_offset);
+ }
+ else {
+ dhcp_append_option(dst_options, dst_len, src_options + src_offset);
+ }
+ src_offset += 2 + src_options[src_offset + 1];
+ }
+ }
+
+ if (src_offset == src_len)
+ return 1;
+ return 0;
+}
+
+/**
+ * DHCP: Finds given occurrence of the option with the given code (op_code)
+ * in "options" field of DHCP-message.
+ *
+ * @param options "options" field of DHCP-message
+ * @param len length of the "options" field
+ * @param op_code code of the option to find
+ * @param op_offset SUCCESS - offset to an option occurrence;
+ * FAULT - offset is set to zero.
+ * @return TRUE - option was find;
+ * FALSE - option wasn't find.
+ */
+static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
+ uint8_t op_code, uint32_t * op_offset) {
+ uint32_t srch_offset = 0;
+ * op_offset = 0;
+
+ while (srch_offset < len) {
+ if (options[srch_offset] == op_code) {
+ * op_offset = srch_offset;
+ return 1;
+ }
+ if (options[srch_offset] == DHCP_ENDOPT)
+ return 0;
+
+ if (options[srch_offset] == DHCP_PADOPT)
+ srch_offset++;
+ else
+ srch_offset += 2 + options[srch_offset + 1];
+ }
+ return 0;
+}
+
+/**
+ * DHCP: Appends new option from one list (src) into the tail
+ * of another option list (dst)
+ *
+ * @param dst_options "options" field of DHCP-message
+ * @param dst_len length of the "options" field (modified)
+ * @param new_option points to an option in another list (src)
+ */
+static void
+dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t * new_option) {
+ memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
+ * dst_len += 2 + *(new_option + 1);
+}
+
+/**
+ * DHCP: This function is used when options with the same code are
+ * presented in both merged lists. In this case information
+ * about the option from one list (src) is combined (complemented)
+ * with information about the option in another list (dst).
+ *
+ * @param dst_options "options" field of DHCP-message
+ * @param dst_len length of the "options" field (modified)
+ * @param dst_offset offset of the option from beginning of the list
+ * @param new_option points to an option in another list (src)
+ */
+static void
+dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint32_t dst_offset, uint8_t * new_option) {
+
+ uint8_t tmp_buffer[1024]; // use to provide safe memcpy
+ uint32_t tail_len;
+
+ // move all subsequent options (allocate size for additional info)
+ tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1];
+
+ memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len);
+ memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)),
+ tmp_buffer, tail_len);
+
+ // add new_content to option
+ memcpy(dst_options + (* dst_len) - tail_len, new_option + 2,
+ * (new_option + 1));
+ dst_options[dst_offset + 1] += * (new_option + 1);
+
+ // correct dst_len
+ * dst_len += * (new_option + 1);
+}
+
+/**
+ * DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
+ */
+static void
+dhcp_send_discover(int fd) {
+ uint32_t packetsize = sizeof(struct iphdr) +
+ sizeof(struct udphdr) + sizeof(struct btphdr);
+ struct btphdr *btph;
+ dhcp_options_t opt;
+
+ memset(ether_packet, 0, packetsize);
+
+ btph = (struct btphdr *) (&ether_packet[
+ sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+ btph -> op = 1;
+ btph -> htype = 1;
+ btph -> hlen = 6;
+ memcpy(btph -> chaddr, get_mac_address(), 6);
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+
+ opt.msg_type = DHCPDISCOVER;
+
+ opt.request_list[DHCP_MASK] = 1;
+ opt.request_list[DHCP_DNS] = 1;
+ opt.request_list[DHCP_ROUTER] = 1;
+ opt.request_list[DHCP_TFTP_SERVER] = 1;
+ opt.request_list[DHCP_BOOTFILE] = 1;
+ opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
+
+ dhcp_encode_options(btph -> vend, &opt);
+
+ fill_udphdr(&ether_packet[sizeof(struct iphdr)],
+ sizeof(struct btphdr) + sizeof(struct udphdr),
+ UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+ fill_iphdr(ether_packet, sizeof(struct btphdr) +
+ sizeof(struct udphdr) + sizeof(struct iphdr),
+ IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF);
+
+ send_ipv4(fd, ether_packet, packetsize);
+}
+
+/**
+ * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
+ */
+static void
+dhcp_send_request(int fd) {
+ uint32_t packetsize = sizeof(struct iphdr) +
+ sizeof(struct udphdr) + sizeof(struct btphdr);
+ struct btphdr *btph;
+ dhcp_options_t opt;
+
+ memset(ether_packet, 0, packetsize);
+
+ btph = (struct btphdr *) (&ether_packet[
+ sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+ btph -> op = 1;
+ btph -> htype = 1;
+ btph -> hlen = 6;
+ memcpy(btph -> chaddr, get_mac_address(), 6);
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+
+ opt.msg_type = DHCPREQUEST;
+ memcpy(&(opt.requested_IP), &dhcp_own_ip, 4);
+ opt.flag[DHCP_REQUESTED_IP] = 1;
+ memcpy(&(opt.server_ID), &dhcp_server_ip, 4);
+ opt.flag[DHCP_SERVER_ID] = 1;
+
+ opt.request_list[DHCP_MASK] = 1;
+ opt.request_list[DHCP_DNS] = 1;
+ opt.request_list[DHCP_ROUTER] = 1;
+ opt.request_list[DHCP_TFTP_SERVER] = 1;
+ opt.request_list[DHCP_BOOTFILE] = 1;
+ opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
+ opt.flag[DHCP_CLIENT_ARCH] = USE_DHCPARCH;
+
+ dhcp_encode_options(btph -> vend, &opt);
+
+ fill_udphdr(&ether_packet[sizeof(struct iphdr)],
+ sizeof(struct btphdr) + sizeof(struct udphdr),
+ UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+ fill_iphdr(ether_packet, sizeof(struct btphdr) +
+ sizeof(struct udphdr) + sizeof(struct iphdr),
+ IPTYPE_UDP, 0, 0xFFFFFFFF);
+
+ send_ipv4(fd, ether_packet, packetsize);
+}
+
+
+/**
+ * DHCP: Sends DHCP-Release message. Releases occupied IP.
+ */
+void dhcp_send_release(int fd) {
+ uint32_t packetsize = sizeof(struct iphdr) +
+ sizeof(struct udphdr) + sizeof(struct btphdr);
+ struct btphdr *btph;
+ dhcp_options_t opt;
+
+ btph = (struct btphdr *) (&ether_packet[
+ sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+ memset(ether_packet, 0, packetsize);
+
+ btph -> op = 1;
+ btph -> htype = 1;
+ btph -> hlen = 6;
+ strcpy((char *) btph -> file, "");
+ memcpy(btph -> chaddr, get_mac_address(), 6);
+ btph -> ciaddr = htonl(dhcp_own_ip);
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+
+ opt.msg_type = DHCPRELEASE;
+ opt.server_ID = dhcp_server_ip;
+ opt.flag[DHCP_SERVER_ID] = 1;
+
+ dhcp_encode_options(btph -> vend, &opt);
+
+ fill_udphdr(&ether_packet[sizeof(struct iphdr)],
+ sizeof(struct btphdr) + sizeof(struct udphdr),
+ UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+ fill_iphdr(ether_packet, sizeof(struct btphdr) +
+ sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP,
+ dhcp_own_ip, dhcp_server_ip);
+
+ send_ipv4(fd, ether_packet, packetsize);
+}
+
+/**
+ * DHCP: Handles DHCP-messages according to Receive-handle diagram.
+ * Changes the state of DHCP-client.
+ *
+ * @param fd socket descriptor
+ * @param packet BootP/DHCP-packet to be handled
+ * @param packetsize length of the packet
+ * @return ZERO - packet handled successfully;
+ * NON ZERO - packet was not handled (e.g. bad format)
+ * @see receive_ether
+ * @see btphdr
+ */
+
+int8_t
+handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) {
+ struct btphdr * btph;
+ struct iphdr * iph;
+ dhcp_options_t opt;
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+ btph = (struct btphdr *) packet;
+ iph = (struct iphdr *) packet - sizeof(struct udphdr) -
+ sizeof(struct iphdr);
+ if (btph -> op != 2)
+ return -1; // it is not Boot Reply
+
+ if (memcmp(btph -> vend, dhcp_magic, 4)) {
+ // It is BootP - RFC 951
+ dhcp_own_ip = htonl(btph -> yiaddr);
+ dhcp_siaddr_ip = htonl(btph -> siaddr);
+ dhcp_server_ip = htonl(iph -> ip_src);
+
+ if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
+ strncpy((char *) dhcp_tftp_name, (char *) btph -> sname,
+ sizeof(btph -> sname));
+ dhcp_tftp_name[sizeof(btph -> sname)] = 0;
+ }
+
+ if (strlen((char *) btph -> file)) {
+ strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
+ dhcp_filename[sizeof(btph -> file)] = 0;
+ }
+
+ dhcp_state = DHCP_STATE_SUCCESS;
+ return 0;
+ }
+
+
+ // decode options
+ if (!dhcp_decode_options(btph -> vend, packetsize -
+ sizeof(struct btphdr) + sizeof(btph -> vend),
+ &opt)) {
+ return -1; // can't decode options
+ }
+
+ if (opt.overload) {
+ int16_t decode_res = 0;
+ uint8_t options[1024]; // buffer for merged options
+ uint32_t opt_len;
+
+ // move 1-st part of options from vend field into buffer
+ opt_len = packetsize - sizeof(struct btphdr) +
+ sizeof(btph -> vend) - 4;
+ memcpy(options, btph -> vend, opt_len + 4);
+
+ // add other parts
+ switch (opt.overload) {
+ case DHCP_OVERLOAD_FILE:
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> file,
+ sizeof(btph -> file));
+ break;
+ case DHCP_OVERLOAD_SNAME:
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> sname,
+ sizeof(btph -> sname));
+ break;
+ case DHCP_OVERLOAD_BOTH:
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> file,
+ sizeof(btph -> file));
+ if (!decode_res)
+ break;
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> sname,
+ sizeof(btph -> sname));
+ break;
+ }
+
+ if (!decode_res)
+ return -1; // bad options in sname/file fields
+
+ // decode merged options
+ if (!dhcp_decode_options(options, opt_len + 4, &opt)) {
+ return -1; // can't decode options
+ }
+ }
+
+ if (!opt.msg_type) {
+ // It is BootP with Extensions - RFC 1497
+ // retrieve conf. settings from BootP - reply
+ dhcp_own_ip = htonl(btph -> yiaddr);
+ dhcp_siaddr_ip = htonl(btph -> siaddr);
+ if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
+ strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname));
+ dhcp_tftp_name[sizeof(btph -> sname)] = 0;
+ }
+
+ if (strlen((char *) btph -> file)) {
+ strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
+ dhcp_filename[sizeof(btph -> file)] = 0;
+ }
+
+ // retrieve DHCP-server IP from IP-header
+ dhcp_server_ip = iph -> htonl(ip_src);
+
+ dhcp_state = DHCP_STATE_SUCCESS;
+ }
+ else {
+ // It is DHCP - RFC 2131 & RFC 2132
+ // opt contains parameters from server
+ switch (dhcp_state) {
+ case DHCP_STATE_SELECT :
+ if (opt.msg_type == DHCPOFFER) {
+ dhcp_own_ip = htonl(btph -> yiaddr);
+ dhcp_server_ip = opt.server_ID;
+ dhcp_send_request(fd);
+ dhcp_state = DHCP_STATE_REQUEST;
+ }
+ return 0;
+ case DHCP_STATE_REQUEST :
+ switch (opt.msg_type) {
+ case DHCPNACK :
+ dhcp_own_ip = 0;
+ dhcp_server_ip = 0;
+ dhcp_state = DHCP_STATE_FAULT;
+ break;
+ case DHCPACK :
+ dhcp_own_ip = htonl(btph -> yiaddr);
+ dhcp_server_ip = opt.server_ID;
+ dhcp_siaddr_ip = htonl(btph -> siaddr);
+ if (opt.flag[DHCP_TFTP_SERVER]) {
+ strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server);
+ }
+ else {
+ strcpy((char *) dhcp_tftp_name, "");
+ if ((opt.overload != DHCP_OVERLOAD_SNAME &&
+ opt.overload != DHCP_OVERLOAD_BOTH) &&
+ !dhcp_siaddr_ip) {
+ strncpy((char *) dhcp_tftp_name,
+ (char *) btph->sname,
+ sizeof(btph -> sname));
+ dhcp_tftp_name[sizeof(btph->sname)] = 0;
+ }
+ }
+
+ if (opt.flag[DHCP_BOOTFILE]) {
+ strcpy((char *) dhcp_filename, (char *) opt.bootfile);
+ }
+ else {
+ strcpy((char *) dhcp_filename, "");
+ if (opt.overload != DHCP_OVERLOAD_FILE &&
+ opt.overload != DHCP_OVERLOAD_BOTH &&
+ strlen((char *) btph -> file)) {
+ strncpy((char *) dhcp_filename,
+ (char *) btph->file,
+ sizeof(btph->file));
+ dhcp_filename[sizeof(btph -> file)] = 0;
+ }
+ }
+
+ dhcp_state = DHCP_STATE_SUCCESS;
+ break;
+ default:
+ break; // Unused DHCP-message - do nothing
+ }
+ break;
+ default :
+ return -1; // Illegal DHCP-client state
+ }
+ }
+
+ if (dhcp_state == DHCP_STATE_SUCCESS) {
+
+ // initialize network entity with real own_ip
+ // to be able to answer for foreign requests
+ set_ipv4_address(dhcp_own_ip);
+
+ if(response_buffer) {
+ if(packetsize <= 1720)
+ memcpy(response_buffer, packet, packetsize);
+ else
+ memcpy(response_buffer, packet, 1720);
+ }
+
+ /* Subnet mask */
+ if (opt.flag[DHCP_MASK]) {
+ /* Router */
+ if (opt.flag[DHCP_ROUTER]) {
+ set_ipv4_router(opt.router_IP);
+ set_ipv4_netmask(opt.subnet_mask);
+ }
+ }
+
+ /* DNS-server */
+ if (opt.flag[DHCP_DNS]) {
+ dns_init(opt.dns_IP, 0, 4);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * DHCP: Converts "255.255.255.255" -> 32-bit long IP
+ *
+ * @param str string to be converted
+ * @param ip in case of SUCCESS - 32-bit long IP
+ in case of FAULT - zero
+ * @return TRUE - IP converted successfully;
+ * FALSE - error condition occurs (e.g. bad format)
+ */
+static uint8_t
+strtoip(int8_t * str, uint32_t * ip) {
+ int8_t ** ptr = &str;
+ int16_t i = 0, res, len;
+ char octet[256];
+
+ * ip = 0;
+
+ while (**ptr != 0) {
+ if (i > 3 || !isdigit(**ptr))
+ return 0;
+ if (strstr((char *) * ptr, ".") != NULL) {
+ len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") -
+ (int8_t *) (* ptr));
+ strncpy(octet, (char *) * ptr, len); octet[len] = 0;
+ * ptr += len;
+ }
+ else {
+ strcpy(octet, (char *) * ptr);
+ * ptr += strlen(octet);
+ }
+ res = strtol(octet, NULL, 10);
+ if ((res > 255) || (res < 0))
+ return 0;
+ * ip = ((* ip) << 8) + res;
+ i++;
+ if (** ptr == '.')
+ (*ptr)++;
+ }
+
+ if (i != 4)
+ return 0;
+ return 1;
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h
new file mode 100644
index 000000000..69dd49d4a
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+#ifndef _DHCP_H_
+#define _DHCP_H_
+
+#include <stdint.h>
+
+#ifdef USE_MTFTP
+#include <netlib/mtftp.h>
+#else
+#include <netlib/tftp.h>
+#endif
+
+/** \struct btphdr
+ * A header for BootP/DHCP-messages.
+ * For more information see RFC 951 / RFC 2131.
+ */
+struct btphdr {
+ uint8_t op; /**< Identifies is it request (1) or reply (2) */
+ uint8_t htype; /**< HW address type (ethernet usually) */
+ uint8_t hlen; /**< HW address length */
+ uint8_t hops; /**< This info used by relay agents (not used) */
+ uint32_t xid; /**< This ID is used to match queries and replies */
+ uint16_t secs; /**< Unused */
+ uint16_t unused; /**< Unused */
+ uint32_t ciaddr; /**< Client IP address (if client knows it) */
+ uint32_t yiaddr; /**< "Your" (client) IP address */
+ uint32_t siaddr; /**< Next server IP address (TFTP server IP) */
+ uint32_t giaddr; /**< Gateway IP address (used by relay agents) */
+ uint8_t chaddr[16]; /**< Client HW address */
+ uint8_t sname[64]; /**< Server host name (TFTP server name) */
+ uint8_t file[128]; /**< Boot file name */
+ uint8_t vend[64]; /**< Optional parameters field (DHCP-options) */
+};
+
+int bootp(char *ret_buffer, filename_ip_t *, unsigned int);
+int dhcpv4(char *ret_buffer, filename_ip_t *);
+void dhcp_send_release(int fd);
+
+/* Handles DHCP-packets, which are detected by receive_ether. */
+extern int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize);
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
new file mode 100644
index 000000000..4deef30f2
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
@@ -0,0 +1,216 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+#include <netlib/udp.h>
+#include <netlib/dhcpv6.h>
+#include <netlib/tftp.h>
+#include <netlib/dns.h>
+
+static uint8_t tid[3];
+static uint32_t dhcpv6_state = -1;
+static filename_ip_t *my_fn_ip;
+
+static void
+generate_transaction_id(void)
+{
+ /* TODO: as per RFC 3315 transaction IDs should be generated randomly */
+ tid[0] = 1;
+ tid[1] = 2;
+ tid[2] = 4;
+}
+
+static void
+send_info_request(int fd)
+{
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ uint32_t payload_length;
+ struct dhcp_message_header *dhcph;
+
+ memset(ether_packet, 0, ETH_MTU_SIZE);
+
+ generate_transaction_id();
+
+ /* Get an IPv6 packet */
+ payload_length = sizeof(struct udphdr) + sizeof(struct dhcp_message_header);
+ fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
+ payload_length, IPTYPE_UDP,
+ get_ipv6_address(), &(all_dhcpv6_ll.addr));
+ fill_udphdr ( ether_packet + sizeof(struct ethhdr) + sizeof(struct ip6hdr),
+ payload_length, DHCP_CLIENT_PORT, DHCP_SERVER_PORT);
+ dhcph = (struct dhcp_message_header *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr) +
+ sizeof(struct udphdr));
+
+ /* Fill in DHCPv6 data */
+ dhcph->type = DHCP_INFORMATION_REQUEST;
+ memcpy( &(dhcph->transaction_id), &tid, 3);
+ dhcph->option.client_id.code = DHCPV6_OPTION_CLIENTID;
+ dhcph->option.client_id.length = 10;
+ dhcph->option.client_id.duid_type = DUID_LL;
+ dhcph->option.client_id.hardware_type = 1;
+ memcpy( &(dhcph->option.client_id.mac),
+ get_mac_address(), 6);
+ dhcph->option.el_time.code = DHCPV6_OPTION_ELAPSED_TIME;
+ dhcph->option.el_time.length = 2;
+ dhcph->option.el_time.time = 0x190; /* 4000 ms */
+ dhcph->option.option_request_option.code = DHCPV6_OPTION_ORO;
+ dhcph->option.option_request_option.length= 6;
+ dhcph->option.option_request_option.option_code[0] = DHCPV6_OPTION_DNS_SERVERS;
+ dhcph->option.option_request_option.option_code[1] = DHCPV6_OPTION_DOMAIN_LIST;
+ dhcph->option.option_request_option.option_code[2] = DHCPV6_OPTION_BOOT_URL;
+
+
+ send_ipv6(fd, ether_packet + sizeof(struct ethhdr),
+ sizeof(struct ethhdr)+ sizeof(struct ip6hdr)
+ + sizeof(struct udphdr)
+ + sizeof( struct dhcp_message_header) );
+}
+
+static int32_t
+dhcpv6_attempt(int fd)
+{
+ int sec;
+
+ // Send information request
+ send_info_request(fd);
+
+ dhcpv6_state = DHCPV6_STATE_SELECT;
+
+ // setting up a timer with a timeout of two seconds
+ for (sec = 0; sec < 2; sec++) {
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether(fd);
+
+ // Wait until client will switch to Final state or Timeout occurs
+ switch (dhcpv6_state) {
+ case DHCP_STATUSCODE_SUCCESS:
+ return 1;
+ case DHCP_STATUSCODE_UNSPECFAIL: //FIXME
+ return 0;
+ }
+ } while (get_timer() > 0);
+ }
+
+ // timeout
+ return 0;
+}
+
+int32_t
+dhcpv6 ( char *ret_buffer, void *fn_ip)
+{
+ int fd;
+
+ my_fn_ip = (filename_ip_t *) fn_ip;
+ fd = my_fn_ip->fd;
+
+ if( !dhcpv6_attempt(fd)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct dhcp6_received_options *
+dhcp6_process_options (uint8_t *option, int32_t option_length)
+{
+ struct dhcp_boot_url *option_boot_url;
+ struct client_identifier *option_clientid;
+ struct server_identifier *option_serverid;
+ struct dhcp_dns *option_dns;
+ struct dhcp_dns_list *option_dns_list;
+ struct dhcp6_gen_option *option_gen;
+ struct dhcp6_received_options *received_options;
+ char buffer[256];
+
+
+ received_options = malloc (sizeof(struct dhcp6_received_options));
+ while (option_length > 0) {
+ switch ((uint16_t) *(option+1)) {
+ case DHCPV6_OPTION_CLIENTID:
+ option_clientid = (struct client_identifier *) option;
+ option = option + option_clientid->length + 4;
+ option_length = option_length - option_clientid->length - 4;
+ received_options->client_id = 1;
+ break;
+ case DHCPV6_OPTION_SERVERID:
+ option_serverid = (struct server_identifier *) option;
+ option = option + option_serverid->length + 4;
+ option_length = option_length - option_serverid->length - 4;
+ received_options->server_id = 1;
+ break;
+ case DHCPV6_OPTION_DNS_SERVERS:
+ option_dns = (struct dhcp_dns *) option;
+ option = option + option_dns->length + 4;
+ option_length = option_length - option_dns->length - 4;
+ memcpy( &(my_fn_ip->dns_ip6),
+ option_dns->p_ip6,
+ IPV6_ADDR_LENGTH);
+ dns_init(0, option_dns->p_ip6, 6);
+ break;
+ case DHCPV6_OPTION_DOMAIN_LIST:
+ option_dns_list = (struct dhcp_dns_list *) option;
+ option = option + option_dns_list->length + 4;
+ option_length = option_length - option_dns_list->length - 4;
+ break;
+ case DHCPV6_OPTION_BOOT_URL:
+ option_boot_url = (struct dhcp_boot_url *) option;
+ option = option + option_boot_url->length + 4;
+ option_length = option_length - option_boot_url->length - 4;
+ strncpy((char *)buffer,
+ (const char *)option_boot_url->url,
+ (size_t)option_boot_url->length);
+ buffer[option_boot_url->length] = 0;
+ if (parse_tftp_args(buffer,
+ (char *)my_fn_ip->server_ip6.addr,
+ (char *)my_fn_ip->filename,
+ (int)my_fn_ip->fd,
+ option_boot_url->length) == -1)
+ return NULL;
+ break;
+ default:
+ option_gen = (struct dhcp6_gen_option *) option;
+ option = option + option_gen->length + 4;
+ option_length = option_length - option_gen->length - 4;
+ }
+ }
+
+ return received_options;
+}
+
+uint32_t
+handle_dhcpv6(uint8_t * packet, int32_t packetsize)
+{
+
+ uint8_t *first_option;
+ int32_t option_length;
+ struct dhcp_message_reply *reply;
+ reply = (struct dhcp_message_reply *) packet;
+
+ if (reply->type == 7)
+ dhcpv6_state = DHCP_STATUSCODE_SUCCESS;
+
+ first_option = packet + 4;
+ option_length = packet + packetsize - first_option;
+ dhcp6_process_options(first_option, option_length);
+
+ return 0;
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h
new file mode 100644
index 000000000..078a9f11f
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h
@@ -0,0 +1,157 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#ifndef _DHCPV6_H_
+#define _DHCPV6_H_
+
+#include <stdint.h>
+#include <netlib/ethernet.h>
+
+#define DHCPV6_STATELESS 0
+#define DHCPV6_STATEFUL 1
+
+/* DHCP port numbers */
+#define DHCP_CLIENT_PORT 546
+#define DHCP_SERVER_PORT 547
+
+/* DHCPv6 message types */
+#define DHCP_SOLICIT 1
+#define DHCP_ADVERTISE 2
+#define DHCP_REQUEST 3
+#define DHCP_CONFIRM 4
+#define DHCP_RENEW 5
+#define DHCP_REBIND 6
+#define DHCP_REPLY 7
+#define DHCP_RELEASE 8
+#define DHCP_DECLINE 9
+#define DHCP_RECONFIGURE 10
+#define DHCP_INFORMATION_REQUEST 11
+#define RELAY_FORW 12
+#define RELAY_REPL 13
+
+/* DHCPv6 option types */
+#define DHCPV6_OPTION_CLIENTID 0x0001
+#define DHCPV6_OPTION_SERVERID 0x0002
+#define DHCPV6_OPTION_IA_NA 3
+#define DHCPV6_OPTION_IA_TA 4
+#define DHCPV6_OPTION_IAADDR 5
+#define DHCPV6_OPTION_ORO 6
+#define DHCPV6_OPTION_PREFEREN 7
+#define DHCPV6_OPTION_ELAPSED_TIME 8
+#define DHCPV6_OPTION_RELAY_MS 9
+#define DHCPV6_OPTION_AUTH 11
+#define DHCPV6_OPTION_UNICAST 12
+#define DHCPV6_OPTION_STATUS_C 13
+#define DHCPV6_OPTION_RAPID_CO 14
+#define DHCPV6_OPTION_USER_CLA 15
+#define DHCPV6_OPTION_VENDOR_C 16
+#define DHCPV6_OPTION_VENDOR_O 17
+#define DHCPV6_OPTION_INTERFAC 18
+#define DHCPV6_OPTION_RECONF_M 19
+#define DHCPV6_OPTION_RECONF_A 20
+#define DHCPV6_OPTION_DNS_SERVERS 23
+#define DHCPV6_OPTION_DOMAIN_LIST 24
+#define DHCPV6_OPTION_BOOT_URL 59
+
+/* DHCPv6 status codes */
+#define DHCP_STATUSCODE_SUCCESS 0
+#define DHCP_STATUSCODE_UNSPECFAIL 1
+#define DHCP_STATUSCODE_NOADDRAVAIL 2
+#define DHCP_STATUSCODE_NOBINDING 3
+#define DHCP_STATUSCODE_NOTONLINK 4
+#define DHCP_STATUSCODE_USEMULTICAST 5
+#define DHCPV6_STATE_SELECT 6
+
+/* DUID types */
+#define DUID_LLT 1 /* DUID based on Link-layer Address Plus Time */
+#define DUID_EN 2 /* DUID based on Assigned by Vendor Based on Enterprise Number */
+#define DUID_LL 3 /* DUID based on Link-layer Address */
+
+/* Prototypes */
+int32_t dhcpv6 ( char *ret_buffer, void *fn_ip);
+uint32_t handle_dhcpv6(uint8_t * , int32_t);
+
+struct dhcp6_gen_option {
+ uint16_t code;
+ uint16_t length;
+};
+
+struct client_identifier {
+ uint16_t code;
+ uint16_t length;
+ uint16_t duid_type;
+ uint16_t hardware_type;
+ uint8_t mac[6];
+};
+
+struct server_identifier {
+ uint16_t code;
+ uint16_t length;
+ uint16_t duid_type;
+ uint16_t hardware_type;
+ uint32_t time;
+ uint8_t mac[6];
+};
+
+struct dhcp_info_request {
+ struct client_identifier client_id;
+ struct elapsed_time {
+ uint16_t code;
+ uint16_t length;
+ uint16_t time;
+ } el_time;
+ struct option_request {
+ uint16_t code;
+ uint16_t length;
+ uint16_t option_code[5];
+ } option_request_option;
+};
+
+struct dhcp_message_header {
+ uint8_t type; /* Message type */
+ uint8_t transaction_id[3]; /* Transaction id */
+ struct dhcp_info_request option;
+};
+
+struct dhcp_dns {
+ uint16_t code;
+ uint16_t length;
+ uint8_t p_ip6[16];
+ uint8_t s_ip6[16];
+}__attribute((packed));
+
+struct dhcp_dns_list {
+ uint16_t code;
+ uint16_t length;
+ uint8_t domain[256];
+}__attribute((packed));
+
+struct dhcp_boot_url {
+ uint16_t type;
+ uint16_t length;
+ uint8_t url[256];
+};
+
+struct dhcp6_received_options {
+ uint8_t filename;
+ uint8_t ip;
+ uint8_t client_id;
+ uint8_t server_id;
+};
+struct dhcp_message_reply {
+ uint8_t type; /* Message type */
+ uint8_t transaction_id[3]; /* Transaction id */
+ struct client_identifier client_id;
+ struct server_identifier server_id;
+};
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c
new file mode 100644
index 000000000..0ab1346c9
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c
@@ -0,0 +1,527 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+/********************** DEFINITIONS & DECLARATIONS ***********************/
+
+#include <dns.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+
+#include <ethernet.h>
+#include <ipv4.h>
+#include <ipv6.h>
+#include <udp.h>
+
+#define DNS_FLAG_MSGTYPE 0xF800 /**< Message type mask (opcode) */
+#define DNS_FLAG_SQUERY 0x0000 /**< Standard query type */
+#define DNS_FLAG_SRESPONSE 0x8000 /**< Standard response type */
+#define DNS_FLAG_RD 0x0100 /**< Recursion desired flag */
+#define DNS_FLAG_RCODE 0x000F /**< Response code mask
+ (stores err.cond.) code */
+#define DNS_RCODE_NERROR 0 /**< "No errors" code */
+
+#define DNS_QTYPE_A 1 /**< A 32-bit IP record type */
+#define DNS_QTYPE_AAAA 0x1c /**< 128-bit IPv6 record type */
+#define DNS_QTYPE_CNAME 5 /**< Canonical name record type */
+
+#define DNS_QCLASS_IN 1 /**< Query class for internet msgs */
+
+/** \struct dnshdr
+ * A header for DNS-messages (see RFC 1035, paragraph 4.1.1).
+ * <p>
+ * DNS-message consist of DNS-header and 4 optional sections,
+ * arranged in the following order:<ul>
+ * <li> DNS-header
+ * <li> question section
+ * <li> answer section
+ * <li> authority section
+ * <li> additional section
+ * </ul>
+ */
+struct dnshdr {
+ uint16_t id; /**< an identifier used to match up replies */
+ uint16_t flags; /**< contains op_code, err_code, etc. */
+ uint16_t qdcount; /**< specifies the number of entries in the
+ question section */
+ uint16_t ancount; /**< specifies the number of entries in the
+ answer section */
+ uint16_t nscount; /**< specifies the number of entries in the
+ authority section */
+ uint16_t arcount; /**< specifies the number of entries in the
+ additional section */
+};
+
+
+/***************************** PROTOTYPES ********************************/
+
+static void
+dns_send_query(int fd, int8_t * domain_name, uint8_t ip_version);
+
+static void
+fill_dnshdr(uint8_t * packet, int8_t * domain_name, uint8_t ip_version);
+
+static uint8_t *
+dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name);
+
+static int8_t
+urltohost(char * url, char * host_name);
+
+static int8_t
+hosttodomain(char * host_name, char * domain_name);
+
+/**************************** LOCAL VARIABLES ****************************/
+
+static uint8_t ether_packet[ETH_MTU_SIZE];
+static int32_t dns_server_ip = 0;
+static uint8_t dns_server_ipv6[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static int32_t dns_result_ip = 0;
+static uint8_t dns_result_ipv6[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static int8_t dns_error = 0; /**< Stores error code or 0 */
+static int8_t dns_domain_name[0x100]; /**< Raw domain name */
+static int8_t dns_domain_cname[0x100]; /**< Canonical domain name */
+
+/**************************** IMPLEMENTATION *****************************/
+
+/**
+ * DNS: Initialize the environment for DNS client.
+ * To perfrom DNS-queries use the function dns_get_ip.
+ *
+ * @param device_socket a socket number used to send and receive packets
+ * @param server_ip DNS-server IPv4 address (e.g. 127.0.0.1)
+ * @return TRUE in case of successful initialization;
+ * FALSE in case of fault (e.g. can't obtain MAC).
+ * @see dns_get_ip
+ */
+int8_t
+dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_version)
+{
+ if(ip_version == 6)
+ memcpy(dns_server_ipv6, _dns_server_ipv6, 16);
+ else
+ dns_server_ip = _dns_server_ip;
+ return 0;
+}
+
+/**
+ * DNS: For given URL retrieves IPv4/IPv6 from DNS-server.
+ * <p>
+ * URL can be given in one of the following form: <ul>
+ * <li> scheme with full path with (without) user and password
+ * <br>(e.g. "http://user:pass@www.host.org/url-path");
+ * <li> host name with url-path
+ * <br>(e.g. "www.host.org/url-path");
+ * <li> nothing but host name
+ * <br>(e.g. "www.host.org");
+ * </ul>
+ *
+ * @param fd socket descriptor
+ * @param url the URL to be resolved
+ * @param domain_ip In case of SUCCESS stores extracted IP.
+ * In case of FAULT stores zeros (0.0.0.0).
+ * @return TRUE - IP successfuly retrieved;
+ * FALSE - error condition occurs.
+ */
+int8_t
+dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version)
+{
+ /* this counter is used so that we abort after 30 DNS request */
+ int32_t i;
+ /* this buffer stores host name retrieved from url */
+ static int8_t host_name[0x100];
+
+ (* domain_ip) = 0;
+
+ // Retrieve host name from URL
+ if (!urltohost((char *) url, (char *) host_name)) {
+ printf("\nERROR:\t\t\tBad URL!\n");
+ return 0;
+ }
+
+ // Reformat host name into a series of labels
+ if (!hosttodomain((char *) host_name, (char *) dns_domain_name)) {
+ printf("\nERROR:\t\t\tBad host name!\n");
+ return 0;
+ }
+
+ // Check if DNS server is presented and accessible
+ if (dns_server_ip == 0) {
+ printf("\nERROR:\t\t\tCan't resolve domain name "
+ "(DNS server is not presented)!\n");
+ return 0;
+ }
+
+ // Use DNS-server to obtain IP
+ if (ip_version == 6)
+ memset(dns_result_ipv6, 0, 16);
+ else
+ dns_result_ip = 0;
+ dns_error = 0;
+ strcpy((char *) dns_domain_cname, "");
+
+ for(i = 0; i < 30; ++i) {
+ // Use canonical name in case we obtained it
+ if (strlen((char *) dns_domain_cname))
+ dns_send_query(fd, dns_domain_cname, ip_version);
+ else
+ dns_send_query(fd, dns_domain_name, ip_version);
+
+ // setting up a timer with a timeout of one seconds
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether(fd);
+ if (dns_error)
+ return 0; // FALSE - error
+ if ((dns_result_ip != 0) && (ip_version == 4)) {
+ memcpy(domain_ip, &dns_result_ip, 4);
+ return 1; // TRUE - success (domain IP retrieved)
+ }
+ else if ((dns_result_ipv6[0] != 0) && (ip_version == 6)) {
+ memcpy(domain_ip, dns_result_ipv6, 16);
+ return 1; // TRUE - success (domain IP retrieved)
+ }
+ } while (get_timer() > 0);
+ }
+
+ printf("\nGiving up after %d DNS requests\n", i);
+ return 0; // FALSE - domain name wasn't retrieved
+}
+
+/**
+ * DNS: Handles DNS-messages according to Receive-handle diagram.
+ * Sets dns_result_ip for given dns_domain_name (see dns_get_ip)
+ * or signals error condition occurs during DNS-resolving process
+ * by setting dns_error flag.
+ *
+ * @param packet DNS-packet to be handled
+ * @param packetsize length of the packet
+ * @return ZERO - packet handled successfully;
+ * NON ZERO - packet was not handled (e.g. bad format)
+ * @see dns_get_ip
+ * @see receive_ether
+ * @see dnshdr
+ */
+int32_t
+handle_dns(uint8_t * packet, int32_t packetsize)
+{
+ struct dnshdr * dnsh = (struct dnshdr *) packet;
+ uint8_t * resp_section = packet + sizeof(struct dnshdr);
+ /* This string stores domain name from DNS-packets */
+ static int8_t handle_domain_name[0x100];
+ int i;
+
+ // verify ID - is it response for our query?
+ if (dnsh -> id != htons(0x1234))
+ return 0;
+
+ // Is it DNS response?
+ if ((dnsh -> flags & htons(DNS_FLAG_MSGTYPE)) != htons(DNS_FLAG_SRESPONSE))
+ return 0;
+
+ // Is error condition occurs? (check error field in incoming packet)
+ if ((dnsh -> flags & htons(DNS_FLAG_RCODE)) != DNS_RCODE_NERROR) {
+ dns_error = 1;
+ return 0;
+ }
+
+ /* Pass all (qdcount) records in question section */
+
+ for (i = 0; i < htons(dnsh -> qdcount); i++) {
+ // pass QNAME
+ resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
+ handle_domain_name);
+ if (resp_section == NULL) {
+ return -1; // incorrect domain name (bad packet)
+ }
+ // pass QTYPE & QCLASS
+ resp_section += 4;
+ }
+
+ /* Handle all (ancount) records in answer section */
+
+ for (i = 0; i < htons(dnsh -> ancount); i++) {
+ // retrieve domain name from the packet
+ resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
+ handle_domain_name);
+
+ if (resp_section == NULL) {
+ return -1; // incorrect domain name (bad packet)
+ }
+
+ // Check the class of the query (should be IN for Internet)
+ if (* (uint16_t *) (resp_section + 2) == htons(DNS_QCLASS_IN)) {
+ // check if retrieved name fit raw or canonical domain name
+ if (!strcmp((char *) handle_domain_name, (char *) dns_domain_name) ||
+ !strcmp((char *) handle_domain_name, (char *) dns_domain_cname)) {
+ switch (htons(* (uint16_t *) resp_section)) {
+
+ case DNS_QTYPE_A :
+ // rdata contains IP
+ dns_result_ip = htonl(* (uint32_t *) (resp_section + 10));
+ return 0; // IP successfully obtained
+
+ case DNS_QTYPE_CNAME :
+ // rdata contains canonical name, store it for further requests
+ if (dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section + 10,
+ dns_domain_cname) == NULL) {
+ // incorrect domain name (bad packet)
+ return -1;
+ }
+ break;
+ case DNS_QTYPE_AAAA :
+ memcpy(dns_result_ipv6, (resp_section + 10), 16);
+ return 0; // IP successfully obtained
+ break;
+ }
+ }
+ // continue with next record in answer section
+ resp_section += htons(* (uint16_t *) (resp_section + 8)) + 10;
+ }
+ }
+ return 0; // Packet successfully handled but IP wasn't obtained
+}
+
+/**
+ * DNS: Sends a standard DNS-query (read request package) to a DNS-server.
+ * DNS-server respones with host IP or signals some error condition.
+ * Responses from the server are handled by handle_dns function.
+ *
+ * @param fd socket descriptor
+ * @param domain_name the domain name given as series of labels preceded
+ * with length(label) and terminated with 0
+ * <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
+ * @see handle_dns
+ */
+static void
+dns_send_query(int fd, int8_t * domain_name, uint8_t ip_version)
+{
+ int qry_len = strlen((char *) domain_name) + 5;
+ int iphdr_len = (ip_version == 4) ? sizeof(struct iphdr) : sizeof(struct ip6hdr);
+ ip6_addr_t server_ipv6;
+
+ uint32_t packetsize = iphdr_len +
+ sizeof(struct udphdr) + sizeof(struct dnshdr) +
+ qry_len;
+
+ memset(ether_packet, 0, packetsize);
+ fill_dnshdr(&ether_packet[
+ iphdr_len + sizeof(struct udphdr)],
+ domain_name,
+ ip_version);
+ fill_udphdr(&ether_packet[iphdr_len],
+ sizeof(struct dnshdr) +
+ sizeof(struct udphdr) + qry_len,
+ UDPPORT_DNSC, UDPPORT_DNSS);
+ if (ip_version == 4) {
+ fill_iphdr(ether_packet,
+ sizeof(struct dnshdr) + sizeof(struct udphdr) +
+ iphdr_len + qry_len,
+ IPTYPE_UDP, 0, dns_server_ip);
+ } else {
+ memcpy(server_ipv6.addr, dns_server_ipv6, 16);
+ fill_ip6hdr(ether_packet,
+ sizeof(struct dnshdr) + sizeof(struct udphdr) + qry_len,
+ IPTYPE_UDP, get_ipv6_address(),
+ &server_ipv6);
+ }
+
+ send_ip(fd, ether_packet, packetsize);
+}
+
+/**
+ * DNS: Creates standard DNS-query package. Places DNS-header
+ * and question section in a packet and fills it with
+ * corresponding information.
+ * <p>
+ * Use this function with similar functions for other network layers
+ * (fill_udphdr, fill_iphdr, fill_ethhdr).
+ *
+ * @param packet Points to the place where ARP-header must be placed.
+ * @param domain_name the domain name given as series of labels preceded
+ * with length(label) and terminated with 0
+ * <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
+ * @see fill_udphdr
+ * @see fill_iphdr
+ * @see fill_ethhdr
+ */
+static void
+fill_dnshdr(uint8_t * packet, int8_t * domain_name, uint8_t ip_version)
+{
+ struct dnshdr * dnsh = (struct dnshdr *) packet;
+ uint8_t * qry_section = packet + sizeof(struct dnshdr);
+
+ dnsh -> id = htons(0x1234);
+ dnsh -> flags = htons(DNS_FLAG_SQUERY) | htons(DNS_FLAG_RD);
+ dnsh -> qdcount = htons(1);
+
+ strcpy((char *) qry_section, (char *) domain_name);
+ qry_section += strlen((char *) domain_name) + 1;
+
+ // fill QTYPE (ask for IP)
+ if (ip_version == 4)
+ * (uint16_t *) qry_section = htons(DNS_QTYPE_A);
+ else
+ * (uint16_t *) qry_section = htons(DNS_QTYPE_AAAA);
+ qry_section += 2;
+ // fill QCLASS (IN is a standard class for Internet)
+ * (uint16_t *) qry_section = htons(DNS_QCLASS_IN);
+}
+
+/**
+ * DNS: Extracts domain name from the question or answer section of
+ * the DNS-message. This function is need to support message
+ * compression requirement (see RFC 1035, paragraph 4.1.4).
+ *
+ * @param dnsh Points at the DNS-header.
+ * @param head Points at the beginning of the domain_name
+ * which has to be extracted.
+ * @param domain_name In case of SUCCESS this string stores extracted name.
+ * In case of FAULT this string is empty.
+ * @return NULL in case of FAULT (domain name > 255 octets);
+ * otherwise pointer to the data following the name.
+ * @see dnshdr
+ */
+static uint8_t *
+dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name)
+{
+ int8_t * tail = domain_name;
+ int8_t * ptr = head;
+ int8_t * next_section = NULL;
+
+ while (1) {
+ if ((ptr[0] & 0xC0) == 0xC0) {
+ // message compressed (reference is used)
+ next_section = ptr + 2;
+ ptr = (int8_t *) dnsh + (htons(* (uint16_t *) ptr) & 0x3FFF);
+ continue;
+ }
+ if (ptr[0] == 0) {
+ // message termination
+ tail[0] = 0;
+ ptr += 1;
+ break;
+ }
+ // maximum length for domain name is 255 octets w/o termination sym
+ if (tail - domain_name + ptr[0] + 1 > 255) {
+ strcpy((char *) domain_name, "");
+ return NULL;
+ }
+ memcpy(tail, ptr, ptr[0] + 1);
+ tail += ptr[0] + 1;
+ ptr += ptr[0] + 1;
+ }
+
+ if (next_section == NULL)
+ next_section = ptr;
+
+ return (uint8_t *) next_section;
+}
+
+/**
+ * DNS: Parses URL and returns host name.
+ * Input string can be given as: <ul>
+ * <li> scheme with full path with (without) user and password
+ * <br>(e.g. "http://user:pass@www.host.org/url-path");
+ * <li> host name with url-path
+ * <br>(e.g. "www.host.org/url-path");
+ * <li> nothing but host name
+ * <br>(e.g. "www.host.org");
+ * </ul>
+ *
+ * @param url string that stores incoming URL
+ * @param host_name In case of SUCCESS this string stores the host name,
+ * In case of FAULT this string is empty.
+ * @return TRUE - host name retrieved,
+ * FALSE - host name > 255 octets or empty.
+ */
+static int8_t
+urltohost(char * url, char * host_name)
+{
+ uint16_t length1;
+ uint16_t length2;
+
+ strcpy(host_name, "");
+
+ if (strstr(url, "://") != NULL)
+ url = strstr(url, "//") + 2; // URL
+
+ if (strstr(url, "@") != NULL) // truncate user & password
+ url = strstr(url, "@") + 1;
+
+ if (strstr(url, "/") != NULL) // truncate url path
+ length1 = strstr(url, "/") - url;
+ else
+ length1 = strlen(url);
+
+ if (strstr(url, ":") != NULL) // truncate port path
+ length2 = strstr(url, ":") - url;
+ else
+ length2 = strlen(url);
+
+ if(length1 > length2)
+ length1 = length2;
+
+ if (length1 == 0)
+ return 0; // string is empty
+ if(length1 >= 256)
+ return 0; // host name is too big
+
+ strncpy(host_name, url, length1);
+ host_name[length1] = 0;
+
+ return 1; // Host name is retrieved
+}
+
+/**
+ * DNS: Transforms host name string into a series of labels
+ * each of them preceded with length(label). 0 is a terminator.
+ * "www.domain.dom" -> "\3,w,w,w,\6,d,o,m,a,i,n,\3,c,o,m,\0"
+ * <p>
+ * This format is used in DNS-messages.
+ *
+ * @param host_name incoming string with the host name
+ * @param domain_name resulting string with series of labels
+ * or empty string in case of FAULT
+ * @return TRUE - host name transformed,
+ * FALSE - host name > 255 octets or label > 63 octets.
+ */
+static int8_t
+hosttodomain(char * host_name, char * domain_name)
+{
+ char * domain_iter = domain_name;
+ char * host_iter = host_name;
+
+ strcpy(domain_name, "");
+
+ if(strlen(host_name) > 255)
+ return 0; // invalid host name (refer to RFC 1035)
+
+ for(; 1; ++host_iter) {
+ if(*host_iter != '.' && *host_iter != 0)
+ continue;
+ *domain_iter = host_iter - host_name;
+ if (*domain_iter > 63) {
+ strcpy(domain_name, "");
+ return 0; // invalid host name (refer to RFC 1035)
+ }
+ ++domain_iter;
+ strncpy(domain_iter, host_name, host_iter - host_name);
+ domain_iter += (host_iter - host_name);
+ if(*host_iter == 0) {
+ *domain_iter = 0;
+ break;
+ }
+ host_name = host_iter + 1;
+ }
+ return 1; // ok
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h
new file mode 100644
index 000000000..82eea4e4d
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+
+#ifndef _DNS_H_
+#define _DNS_H_
+
+#include <stdint.h>
+
+/* Initialize the environment for DNS client. */
+extern int8_t dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_version);
+
+/* For given URL retrieves IPv4 from DNS-server. */
+extern int8_t dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version);
+
+/* Handles DNS-packets, which are detected by receive_ether. */
+extern int32_t handle_dns(uint8_t * packet, int32_t packetsize);
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
new file mode 100644
index 000000000..bbfd6d1c3
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
@@ -0,0 +1,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);
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.h
new file mode 100644
index 000000000..e541c8f8e
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+#ifndef _ETHERNET_H
+#define _ETHERNET_H
+
+#include <stdint.h>
+
+#define ETH_MTU_SIZE 1518 /**< Maximum Transfer Unit */
+#define ETH_ALEN 6 /**< HW address length */
+#define ETHERTYPE_IP 0x0800
+#define ETHERTYPE_IPv6 0x86DD
+#define ETHERTYPE_ARP 0x0806
+
+/** \struct ethhdr
+ * A header for Ethernet-packets.
+ */
+struct ethhdr {
+ uint8_t dest_mac[ETH_ALEN]; /**< Destination HW address */
+ uint8_t src_mac[ETH_ALEN]; /**< Source HW address */
+ uint16_t type; /**< Next level protocol type */
+};
+
+/* Initializes ethernet layer */
+extern void set_mac_address(const uint8_t * own_mac);
+extern const uint8_t * get_mac_address(void);
+
+/* Receives and handles packets, according to Receive-handle diagram */
+extern int32_t receive_ether(int fd);
+
+/* Sends an ethernet frame. */
+extern int send_ether(int fd, void* buffer, int len);
+
+/* fills ethernet header */
+extern void fill_ethhdr(uint8_t * packet, uint16_t eth_type,
+ const uint8_t * src_mac, const uint8_t * dest_mac);
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c
new file mode 100644
index 000000000..be6cc110f
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c
@@ -0,0 +1,391 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+#include <netlib/icmpv6.h>
+#include <netlib/ndp.h>
+#include <netlib/dhcpv6.h>
+
+static int ra_received = 0;
+
+/**
+ * NET:
+ * @param fd socket fd
+ */
+void
+send_router_solicitation (int fd)
+{
+ ip6_addr_t dest_addr;
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ struct packeth headers;
+
+ headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ /* Destination is "All routers multicast address" (link-local) */
+ dest_addr.part.prefix = all_routers_ll.addr.part.prefix;
+ dest_addr.part.interface_id = all_routers_ll.addr.part.interface_id;
+
+
+ /* Fill IPv6 header */
+ fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
+ ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation),
+ 0x3a, //ICMPV6
+ get_ipv6_address(), &dest_addr);
+
+ /* Fill ICMPv6 message */
+ headers.icmp6h->type = ICMPV6_ROUTER_SOLICITATION;
+ headers.icmp6h->code = 0;
+ headers.icmp6h->icmp6body.router_solicit.lladdr.type = 1;
+ headers.icmp6h->icmp6body.router_solicit.lladdr.length = 1;
+ memcpy( &(headers.icmp6h->icmp6body.router_solicit.lladdr.mac),
+ get_mac_address(), 6);
+
+ send_ip (fd, headers.ip6h, sizeof(struct ip6hdr) +
+ ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation));
+}
+
+/**
+ * NET: Process prefix option in Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+handle_prefixoption (uint8_t *option)
+{
+ ip6_addr_t prefix;
+ struct ip6addr_list_entry *new_address;
+ struct option_prefix *prefix_option;
+ struct prefix_info *prfx_info;
+
+ prefix_option = (struct option_prefix *) option;
+ memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH);
+
+ /* Link-local adresses in RAs are nonsense */
+ if ( (IPV6_LL_PREFIX & (prefix_option->prefix.part.prefix)) == IPV6_LL_PREFIX )
+ return;
+
+ if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime)
+ return;
+
+ /* Add address created from prefix to IPv6 address list */
+ new_address = ip6_prefix2addr (prefix);
+ if (!new_address)
+ return;
+
+ /* Process only prefixes we don't already have an adress from */
+ if (!unknown_prefix (&new_address->addr)) {
+ return;
+ }
+
+ /* Fill struct prefix_info from data in RA and store it in new_address */
+ prfx_info = ip6_create_prefix_info();
+ if (!prfx_info)
+ return;
+ memcpy (&(new_address->prfx_info), prfx_info, sizeof(struct prefix_info));
+
+ /* Add prefix received in RA to list of known prefixes */
+ ip6addr_add (new_address);
+}
+
+/**
+ * NET: Process source link layer addresses in Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+handle_source_lladdr ( struct option_ll_address *option, struct router *rtr)
+{
+ memcpy (&(rtr->mac), &(option->mac), 6);
+}
+
+/**
+ * NET: Process ICMPv6 options in Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+process_ra_options (uint8_t *option, int32_t option_length, struct router *r)
+{
+ while (option_length > 0) {
+ switch (*option) {
+ case ND_OPTION_SOURCE_LL_ADDR:
+ handle_source_lladdr ((struct option_ll_address *) option, r);
+ break;
+ case ND_OPTION_PREFIX_INFO:
+ handle_prefixoption(option);
+ break;
+ default:
+ break;
+ }
+ //option+1 is the length field. length is in units of 8 bytes
+ option_length = option_length - (*(option+1) * 8);
+ option = option + (*(option+1) * 8);
+ }
+
+ return;
+}
+
+/**
+ * NET: Process Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+handle_ra (struct icmp6hdr *icmp6h, uint8_t *ip6_packet)
+{
+ uint8_t *first_option;
+ int32_t option_length;
+ struct ip6hdr *ip6h;
+ struct router_advertisement *ra;
+ struct router *rtr;
+ ip6_addr_t *rtr_ip;
+ uint8_t rtr_mac[] = {0, 0, 0, 0, 0, 0};
+
+ ip6h = (struct ip6hdr *) ip6_packet;
+ ra = (struct router_advertisement *) &icmp6h->icmp6body.ra;
+ rtr_ip = (ip6_addr_t *) &ip6h->src;
+
+ rtr = find_router (&(ip6h->src));
+ if (!rtr) {
+ rtr = router_create (rtr_mac, rtr_ip);
+ router_add (rtr);
+ }
+
+ /* store info from router advertisement in router struct */
+ rtr->lifetime = ra->router_lifetime;
+ rtr->reachable_time = ra->reachable_time;
+ rtr->retrans_timer = ra->retrans_timer;
+
+ /* save flags concerning address (auto-) configuration */
+ ip6_state.managed_mode = ra->flags.managed;
+ ip6_state.other_config = ra->flags.other;
+
+ /* Process ICMPv6 options in Router Advertisement */
+ first_option = (uint8_t *) icmp6h + ICMPv6_HEADER_SIZE + 12;
+ option_length = (uint8_t *) icmp6h + ip6h->pl - first_option;
+ process_ra_options( (uint8_t *) first_option, option_length, rtr);
+
+ ra_received = 1;
+}
+
+int is_ra_received(void)
+{
+ return ra_received;
+}
+
+/**
+ * NET:
+ *
+ * @param fd socket fd
+ * @param ip6_addr_t *dest_ip6
+ */
+void
+send_neighbour_solicitation (int fd, ip6_addr_t *dest_ip6)
+{
+ ip6_addr_t snma;
+
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ struct packeth headers;
+
+ memset(ether_packet, 0, ETH_MTU_SIZE);
+ headers.ethh = (struct ethhdr *) ether_packet;
+ headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ /* Fill IPv6 header */
+ snma.part.prefix = IPV6_SOLIC_NODE_PREFIX;
+ snma.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID;
+ snma.addr[13] = dest_ip6->addr[13];
+ snma.addr[14] = dest_ip6->addr[14];
+ snma.addr[15] = dest_ip6->addr[15];
+ fill_ip6hdr((uint8_t *) headers.ip6h,
+ ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_solicitation),
+ 0x3a, //ICMPv6
+ get_ipv6_address(), &snma);
+
+ /* Fill ICMPv6 message */
+ headers.icmp6h->type = ICMPV6_NEIGHBOUR_SOLICITATION;
+ headers.icmp6h->code = 0;
+ memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.target),
+ dest_ip6, IPV6_ADDR_LENGTH );
+ headers.icmp6h->icmp6body.nghb_solicit.lladdr.type = 1;
+ headers.icmp6h->icmp6body.nghb_solicit.lladdr.length = 1;
+ memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.lladdr.mac),
+ get_mac_address(), 6);
+
+ send_ip (fd, ether_packet + sizeof(struct ethhdr),
+ sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_solicitation));
+}
+
+/**
+ * NET:
+ *
+ * @param fd socket fd
+ * @param ip6_packet pointer to an IPv6 packet
+ * @param icmp6hdr pointer to the icmp6 header in ip6_packet
+ * @param na_flags Neighbour advertisment flags
+ */
+static void
+send_neighbour_advertisement (int fd, struct neighbor *target)
+{
+ struct na_flags na_adv_flags;
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ struct packeth headers;
+
+
+ headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ /* Fill IPv6 header */
+ fill_ip6hdr(ether_packet + sizeof(struct ethhdr),
+ ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_advertisement),
+ 0x3a, //ICMPv6
+ get_ipv6_address(), (ip6_addr_t *) &(target->ip.addr));
+
+ /* Fill ICMPv6 message */
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
+ &(target->ip.addr), IPV6_ADDR_LENGTH );
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 1;
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
+ get_mac_address(), 6);
+
+ na_adv_flags.is_router = 0;
+ na_adv_flags.na_is_solicited = 1;
+ na_adv_flags.override = 1;
+
+ headers.icmp6h->type = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
+ headers.icmp6h->code = 0;
+ headers.icmp6h->icmp6body.nghb_adv.router = na_adv_flags.is_router;
+
+ headers.icmp6h->icmp6body.nghb_adv.solicited = na_adv_flags.na_is_solicited;
+ headers.icmp6h->icmp6body.nghb_adv.override = na_adv_flags.override;
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 2;
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
+
+ memset( &(headers.icmp6h->icmp6body.nghb_adv.target), 0,
+ IPV6_ADDR_LENGTH );
+
+ if( na_adv_flags.na_is_solicited ) {
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
+ get_ipv6_address(), IPV6_ADDR_LENGTH);
+ }
+
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
+ get_mac_address(), 6);
+
+ send_ip (fd, ether_packet + sizeof(struct ethhdr),
+ sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_advertisement));
+}
+
+/**
+ * NET:
+ *
+ * @param fd socket fd
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static int8_t
+handle_na (int fd, uint8_t *packet)
+{
+ struct neighbor *n = NULL;
+ struct packeth headers;
+ ip6_addr_t ip;
+
+ headers.ethh = (struct ethhdr *) packet;
+ headers.ip6h = (struct ip6hdr *) ((unsigned char *) headers.ethh +
+ sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ memcpy(&(ip.addr), &(headers.ip6h->src), IPV6_ADDR_LENGTH);
+
+ n = find_neighbor (&ip);
+
+ if (!n) {
+ n= (struct neighbor *)
+ neighbor_create( packet, &headers );
+ if (!n)
+ return 0;
+ if (!neighbor_add(n))
+ return 0;
+ } else {
+ memcpy (&(n->mac), &(headers.ethh->src_mac[0]), 6);
+
+ if (n->eth_len > 0) {
+ struct ethhdr * ethh = (struct ethhdr *) &(n->eth_frame);
+ memcpy(ethh->dest_mac, &(n->mac), 6);
+ send_ether (fd, &(n->eth_frame), n->eth_len + sizeof(struct ethhdr));
+ n->eth_len = 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * NET: Handles ICMPv6 messages
+ *
+ * @param fd socket fd
+ * @param ip6_packet pointer to an IPv6 packet
+ * @param packetsize size of ipv6_packet
+ */
+int8_t
+handle_icmpv6 (int fd, struct ethhdr *etherhdr,
+ uint8_t *ip6_packet)
+{
+
+ struct icmp6hdr *received_icmp6 = NULL;
+ struct ip6hdr *received_ip6 = NULL;
+ struct neighbor target;
+
+ received_ip6 = (struct ip6hdr *) ip6_packet;
+ received_icmp6 = (struct icmp6hdr *) (ip6_packet +
+ sizeof(struct ip6hdr));
+ memcpy( &(target.ip.addr), &(received_ip6->src),
+ IPV6_ADDR_LENGTH );
+ memcpy( &(target.mac), etherhdr->src_mac, 6);
+
+ /* process ICMPv6 types */
+ switch(received_icmp6->type) {
+ case ICMPV6_NEIGHBOUR_SOLICITATION:
+ send_neighbour_advertisement(fd, &target);
+ break;
+ case ICMPV6_NEIGHBOUR_ADVERTISEMENT:
+ handle_na(fd, (uint8_t *) ip6_packet - sizeof(struct ethhdr));
+ break;
+ case ICMPV6_ROUTER_ADVERTISEMENT:
+ handle_ra(received_icmp6, (uint8_t *) received_ip6);
+ break;
+ default:
+ return -1;
+ }
+
+ return 1;
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.h
new file mode 100644
index 000000000..32797973d
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.h
@@ -0,0 +1,135 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#ifndef _ICMPV6_H_
+#define _ICMPV6_H_
+
+#include <stdint.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+
+#define __ICMPV6_DEBUG__
+
+#ifdef __ICMPV6_DEBUG__
+#define ICMPV6_DEBUG_PRINT(format, ...) printf(format, ## __VA_ARGS__)
+#else
+#define ICMPV6_DEBUG_PRINT(format, ...)
+#endif
+
+#define ICMPv6_HEADER_SIZE 4 /* Size of common fields */
+#define IPTYPE_ICMPV6 0x3a
+
+/* Error message types */
+#define ICMPV6_DEST_UNREACHABLE 1 /* Destination unreachable */
+#define ICMPV6_PACKET_TOO_BIG 2 /* Packet too big */
+#define ICMPV6_TIME_EXCEEDED 3 /* Time exceeded */
+#define ICMPV6_PARAM_PROBLEM 4 /* Parameter problem */
+
+/* Informational message types */
+#define ICMPV6_ECHO_REQUEST 128 /* Echo request */
+#define ICMPV6_ECHO_REPLY 129 /* Echo reply */
+#define ICMPV6_MCAST_LISTENER_QUERY 130 /* Multicast listener query */
+#define ICMPV6_MCAST_LISTENER_REPORT 131 /* Multicast listener report */
+#define ICMPv6 MCAST_LISTENER_DONE 132 /* Multicast listener done */
+#define ICMPV6_ROUTER_SOLICITATION 133 /* Router solicitation */
+#define ICMPV6_ROUTER_ADVERTISEMENT 134 /* Router advertisement */
+#define ICMPV6_NEIGHBOUR_SOLICITATION 135 /* Neighbor solicitation */
+#define ICMPV6_NEIGHBOUR_ADVERTISEMENT 136 /* Neighbor advertisement */
+#define ICMPV6_REDIRECT_MSG 137 /* Redirect message */
+
+/******** Functions *******************/
+int8_t handle_icmpv6 (int fd, struct ethhdr *etherhdr, uint8_t *ip6_packet);
+void send_neighbour_solicitation(int fd, ip6_addr_t *target_ip6);
+void send_router_solicitation(int fd);
+int is_ra_received(void);
+
+/* Prefix information */
+struct option_prefix {
+ uint8_t type;
+ uint8_t length;
+ uint8_t prefix_length;
+ uint8_t onlink:1,
+ autom:1,
+ not_router:1,
+ not_site_prefix:1,
+ reserved:4;
+ uint32_t valid_lifetime;
+ uint32_t preferred_lifetime;
+ uint32_t reserved2;
+ ip6_addr_t prefix;
+} __attribute((packed));
+
+/* Neighbour advertisement/solicitation flags */
+struct na_flags {
+ uint8_t is_router:1, /* sender (we) is a router */
+ na_is_solicited:1, /* this NA was solicited (asked for) */
+ override:1, /* receiver shall override its cache entries */
+ unused:5;
+}__attribute((packed));
+
+/* Source/Target Link-layer address */
+struct option_ll_address{
+ uint8_t type;
+ uint8_t length;
+ uint8_t mac[ETH_ALEN];
+} __attribute((packed));
+
+struct neighbour_solicitation {
+ uint32_t router:1,
+ solicited:1,
+ override:1,
+ reserved:29;
+ ip6_addr_t target;
+ struct option_ll_address lladdr;
+} __attribute((packed));
+
+struct neighbour_advertisement {
+ uint32_t router:1,
+ solicited:1,
+ override:1,
+ reserved:29;
+ ip6_addr_t target;
+ struct option_ll_address lladdr;
+} __attribute((packed));
+
+struct router_solicitation {
+ uint32_t reserved;
+ struct option_ll_address lladdr;
+} __attribute((packed));
+
+struct router_advertisement {
+ uint8_t curr_hop_limit;
+ struct raflags {
+ uint8_t managed:1,
+ other:1,
+ reserved:6;
+ } flags;
+ uint16_t router_lifetime;
+ uint32_t reachable_time;
+ uint32_t retrans_timer;
+ struct option_prefix prefix;
+ struct option_ll_address ll_addr;
+} __attribute((packed));
+
+struct icmp6hdr {
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ union {
+ struct neighbour_solicitation nghb_solicit;
+ struct neighbour_advertisement nghb_adv;
+ struct router_solicitation router_solicit;
+ struct router_advertisement ra;
+ } icmp6body;
+} __attribute((packed));
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c
new file mode 100644
index 000000000..8185de5e1
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c
@@ -0,0 +1,904 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+
+/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+
+#include <ipv4.h>
+#include <udp.h>
+#include <tcp.h>
+#include <ethernet.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <string.h>
+
+/* ARP Message types */
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+/* ARP talbe size (+1) */
+#define ARP_ENTRIES 10
+
+/* ICMP Message types */
+#define ICMP_ECHO_REPLY 0
+#define ICMP_DST_UNREACHABLE 3
+#define ICMP_SRC_QUENCH 4
+#define ICMP_REDIRECT 5
+#define ICMP_ECHO_REQUEST 8
+#define ICMP_TIME_EXCEEDED 11
+#define ICMP_PARAMETER_PROBLEM 12
+#define ICMP_TIMESTAMP_REQUEST 13
+#define ICMP_TIMESTAMP_REPLY 14
+#define ICMP_INFORMATION_REQUEST 15
+#define ICMP_INFORMATION_REPLY 16
+
+/** \struct arp_entry
+ * A entry that describes a mapping between IPv4- and MAC-address.
+ */
+typedef struct arp_entry arp_entry_t;
+struct arp_entry {
+ uint32_t ipv4_addr;
+ uint8_t mac_addr[6];
+ uint8_t eth_frame[ETH_MTU_SIZE];
+ int eth_len;
+ int pkt_pending;
+};
+
+/** \struct icmphdr
+ * ICMP packet
+ */
+struct icmphdr {
+ unsigned char type;
+ unsigned char code;
+ unsigned short int checksum;
+ union {
+ /* for type 3 "Destination Unreachable" */
+ unsigned int unused;
+ /* for type 0 and 8 */
+ struct echo {
+ unsigned short int id;
+ unsigned short int seq;
+ } echo;
+ } options;
+ union {
+ /* payload for destination unreachable */
+ struct dun {
+ unsigned char iphdr[20];
+ unsigned char data[64];
+ } dun;
+ /* payload for echo or echo reply */
+ /* maximum size supported is 84 */
+ unsigned char data[84];
+ } payload;
+};
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static unsigned short
+checksum(unsigned short *packet, int words);
+
+static void
+arp_send_request(int fd, uint32_t dest_ip);
+
+static void
+arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac);
+
+static void
+fill_arphdr(uint8_t * packet, uint8_t opcode,
+ const uint8_t * src_mac, uint32_t src_ip,
+ const uint8_t * dest_mac, uint32_t dest_ip);
+
+static arp_entry_t*
+lookup_mac_addr(uint32_t ipv4_addr);
+
+static void
+fill_udp_checksum(struct iphdr *ipv4_hdr);
+
+static int8_t
+handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize);
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/* Routing parameters */
+static uint32_t own_ip = 0;
+static uint32_t multicast_ip = 0;
+static uint32_t router_ip = 0;
+static uint32_t subnet_mask = 0;
+
+/* helper variables */
+static uint32_t ping_dst_ip;
+static const uint8_t null_mac_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+static uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+/* There are only (ARP_ENTRIES-1) effective entries because
+ * the entry that is pointed by arp_producer is never used.
+ */
+static unsigned int arp_consumer = 0;
+static unsigned int arp_producer = 0;
+static arp_entry_t arp_table[ARP_ENTRIES];
+static arp_entry_t pending_pkt;
+
+/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
+int (*send_ip) (int fd, void *, int);
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * IPv4: Initialize the environment for the IPv4 layer.
+ */
+static void
+ipv4_init(void)
+{
+ int i;
+
+ ping_dst_ip = 0;
+
+ // clear ARP table
+ arp_consumer = 0;
+ arp_producer = 0;
+ for(i=0; i<ARP_ENTRIES; ++i) {
+ arp_table[i].ipv4_addr = 0;
+ memset(arp_table[i].mac_addr, 0, 6);
+ arp_table[i].eth_len = 0;
+ arp_table[i].pkt_pending = 0;
+ }
+
+ /* Set IP send function to send_ipv4() */
+ send_ip = &send_ipv4;
+}
+
+/**
+ * IPv4: Set the own IPv4 address.
+ *
+ * @param _own_ip client IPv4 address (e.g. 127.0.0.1)
+ */
+void
+set_ipv4_address(uint32_t _own_ip)
+{
+ own_ip = _own_ip;
+ ipv4_init();
+}
+
+/**
+ * IPv4: Get the own IPv4 address.
+ *
+ * @return client IPv4 address (e.g. 127.0.0.1)
+ */
+uint32_t
+get_ipv4_address(void)
+{
+ return own_ip;
+}
+
+/**
+ * IPv4: Set the IPv4 multicast address.
+ *
+ * @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255)
+ */
+void
+set_ipv4_multicast(uint32_t _multicast_ip)
+{
+ // is this IP Multicast out of range (224.0.0.0 - 239.255.255.255)
+ if((htonl(_multicast_ip) < 0xE0000000)
+ || (htonl(_multicast_ip) > 0xEFFFFFFF)) {
+ multicast_ip = 0;
+ memset(multicast_mac, 0xFF, 6);
+ return;
+ }
+
+ multicast_ip = _multicast_ip;
+ multicast_mac[0] = 0x01;
+ multicast_mac[1] = 0x00;
+ multicast_mac[2] = 0x5E;
+ multicast_mac[3] = (uint8_t) 0x7F & (multicast_ip >> 16);
+ multicast_mac[4] = (uint8_t) 0xFF & (multicast_ip >> 8);
+ multicast_mac[5] = (uint8_t) 0xFF & (multicast_ip >> 0);
+}
+
+/**
+ * IPv4: Get the IPv4 multicast address.
+ *
+ * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set)
+ */
+uint32_t
+get_ipv4_multicast(void)
+{
+ return multicast_ip;
+}
+
+/**
+ * IPv4: Set the routers IPv4 address.
+ *
+ * @param _router_ip router IPv4 address
+ */
+void
+set_ipv4_router(uint32_t _router_ip)
+{
+ router_ip = _router_ip;
+ ipv4_init();
+}
+
+/**
+ * IPv4: Get the routers IPv4 address.
+ *
+ * @return router IPv4 address
+ */
+uint32_t
+get_ipv4_router(void)
+{
+ return router_ip;
+}
+
+/**
+ * IPv4: Set the subnet mask.
+ *
+ * @param _subnet_mask netmask of the own IPv4 address
+ */
+void
+set_ipv4_netmask(uint32_t _subnet_mask)
+{
+ subnet_mask = _subnet_mask;
+ ipv4_init();
+}
+
+/**
+ * IPv4: Get the subnet mask.
+ *
+ * @return netmask of the own IPv4 address
+ */
+uint32_t
+get_ipv4_netmask(void)
+{
+ return subnet_mask;
+}
+
+/**
+ * IPv4: Creates IP-packet. Places IP-header in a packet and fills it
+ * with corresponding information.
+ * <p>
+ * Use this function with similar functions for other network layers
+ * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr).
+ *
+ * @param packet Points to the place where IP-header must be placed.
+ * @param packetsize Size of the packet in bytes incl. this hdr and data.
+ * @param ip_proto Type of the next level protocol (e.g. UDP).
+ * @param ip_src Sender IP address
+ * @param ip_dst Receiver IP address
+ * @see iphdr
+ * @see fill_ethhdr
+ * @see fill_udphdr
+ * @see fill_dnshdr
+ * @see fill_btphdr
+ */
+void
+fill_iphdr(uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) {
+ struct iphdr * iph = (struct iphdr *) packet;
+
+ iph -> ip_hlv = 0x45;
+ iph -> ip_tos = 0x10;
+ iph -> ip_len = htons(packetsize);
+ iph -> ip_id = htons(0);
+ iph -> ip_off = 0;
+ iph -> ip_ttl = 0xFF;
+ iph -> ip_p = ip_proto;
+ iph -> ip_src = htonl(ip_src);
+ iph -> ip_dst = htonl(ip_dst);
+ iph -> ip_sum = 0;
+}
+
+/**
+ * IPv4: Handles IPv4-packets according to Receive-handle diagram.
+ *
+ * @param fd socket fd
+ * @param ip_packet IP-packet to be handled
+ * @param packetsize Length of the packet
+ * @return ZERO - packet handled successfully;
+ * NON ZERO - packet was not handled (e.g. bad format)
+ * @see receive_ether
+ * @see iphdr
+ */
+int8_t
+handle_ipv4(int fd, uint8_t * ip_packet, int32_t packetsize)
+{
+ struct iphdr * iph;
+ int32_t old_sum;
+ static uint8_t ip_heap[65536 + ETH_MTU_SIZE];
+
+ if (packetsize < sizeof(struct iphdr))
+ return -1; // packet is too small
+
+ iph = (struct iphdr * ) ip_packet;
+
+ /* Drop it if destination IPv4 address is no IPv4 Broadcast, no
+ * registered IPv4 Multicast and not our Unicast address
+ */
+ if((multicast_ip == 0 && iph->ip_dst >= 0xE0000000 && iph->ip_dst <= 0xEFFFFFFF)
+ || (multicast_ip != iph->ip_dst && iph->ip_dst != 0xFFFFFFFF &&
+ own_ip != 0 && iph->ip_dst != own_ip)) {
+ return -1;
+ }
+
+ old_sum = iph -> ip_sum;
+ iph -> ip_sum = 0;
+ if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1))
+ return -1; // Wrong IP checksum
+
+ // is it the first fragment in a packet?
+ if (((iph -> ip_off) & 0x1FFF) == 0) {
+ // is it part of more fragments?
+ if (((iph -> ip_off) & 0x2000) == 0x2000) {
+ memcpy(ip_heap, ip_packet, iph->ip_len);
+ return 0;
+ }
+ }
+ // it's not the first fragment
+ else {
+ // get the first fragment
+ struct iphdr * iph_first = (struct iphdr * ) ip_heap;
+
+ // is this fragment not part of the first one, then exit
+ if ((iph_first->ip_id != iph->ip_id ) ||
+ (iph_first->ip_p != iph->ip_p ) ||
+ (iph_first->ip_src != iph->ip_src) ||
+ (iph_first->ip_dst != iph->ip_dst)) {
+ return 0;
+ }
+
+ // this fragment is part of the first one!
+ memcpy(ip_heap + sizeof(struct iphdr) +
+ ((iph -> ip_off) & 0x1FFF) * 8,
+ ip_packet + sizeof(struct iphdr),
+ iph -> ip_len - sizeof(struct iphdr));
+
+ // is it part of more fragments? Then return.
+ if (((iph -> ip_off) & 0x2000) == 0x2000) {
+ return 0;
+ }
+
+ // packet is completly reassambled now!
+
+ // recalculate ip_len and set iph and ip_packet to the
+ iph_first->ip_len = iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8;
+
+ // set iph and ip_packet to the resulting packet.
+ ip_packet = ip_heap;
+ iph = (struct iphdr * ) ip_packet;
+ }
+
+ switch (iph -> ip_p) {
+ case IPTYPE_ICMP:
+ return handle_icmp(fd, iph, ip_packet + sizeof(struct iphdr),
+ iph -> ip_len - sizeof(struct iphdr));
+ case IPTYPE_UDP:
+ return handle_udp(fd, ip_packet + sizeof(struct iphdr),
+ iph -> ip_len - sizeof(struct iphdr));
+ case IPTYPE_TCP:
+ return handle_tcp(ip_packet + sizeof(struct iphdr),
+ iph -> ip_len - sizeof(struct iphdr));
+ default:
+ break;
+ }
+ return -1; // Unknown protocol
+}
+
+/**
+ * IPv4: Send IPv4-packets.
+ *
+ * Before the packet is sent there are some patcches performed:
+ * - IPv4 source address is replaced by our unicast IPV4 address
+ * if it is set to 0 or 1
+ * - IPv4 destination address is replaced by our multicast IPV4 address
+ * if it is set to 1
+ * - IPv4 checksum is calculaded.
+ * - If payload type is UDP, then the UDP checksum is calculated also.
+ *
+ * We send an ARP request first, if this is the first packet sent to
+ * the declared IPv4 destination address. In this case we store the
+ * the packet and send it later if we receive the ARP response.
+ * If the MAC address is known already, then we send the packet immediately.
+ * If there is already an ARP request pending, then we drop this packet
+ * and send again an ARP request.
+ *
+ * @param fd socket fd
+ * @param ip_packet IP-packet to be handled
+ * @param packetsize Length of the packet
+ * @return -2 - packet dropped (MAC address not resolved - ARP request pending)
+ * -1 - packet dropped (bad format)
+ * 0 - packet stored (ARP request sent - packet will be sent if
+ * ARP response is received)
+ * >0 - packet send (number of transmitted bytes is returned)
+ *
+ * @see receive_ether
+ * @see iphdr
+ */
+int
+send_ipv4(int fd, void* buffer, int len)
+{
+ arp_entry_t *arp_entry = 0;
+ struct iphdr *ip;
+ const uint8_t *mac_addr = 0;
+ uint32_t ip_dst = 0;
+
+ if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE)
+ return -1;
+
+ ip = (struct iphdr *) buffer;
+
+ /* Replace source IPv4 address with our own unicast IPv4 address
+ * if it's 0 (= own unicast source address not specified).
+ */
+ if(ip->ip_src == 0) {
+ ip->ip_src = htonl( own_ip );
+ }
+ /* Replace source IPv4 address with our unicast IPv4 address and
+ * replace destination IPv4 address with our multicast IPv4 address
+ * if source address is set to 1.
+ */
+ else if(ip->ip_src == 1) {
+ ip->ip_src = htonl( own_ip );
+ ip->ip_dst = htonl( multicast_ip );
+ }
+
+ // Calculate the IPv4 checksum
+ ip->ip_sum = 0;
+ ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1);
+
+ // if payload type is UDP, then we need to calculate the
+ // UDP checksum that depends on the IP header
+ if(ip->ip_p == IPTYPE_UDP) {
+ fill_udp_checksum(ip);
+ }
+
+ ip_dst = ip->ip_dst;
+ // Check if the MAC address is already cached
+ if(~ip->ip_dst == 0
+ || ( ((~subnet_mask) & ip->ip_dst) == ~subnet_mask &&
+ ( subnet_mask & ip->ip_dst) == (subnet_mask & own_ip))) {
+ arp_entry = &arp_table[arp_producer];
+ mac_addr = broadcast_mac;
+ }
+ else if(ip->ip_dst == multicast_ip) {
+ arp_entry = &arp_table[arp_producer];
+ mac_addr = multicast_mac;
+ }
+ else {
+ // Check if IP address is in the same subnet as we are
+ if((subnet_mask & own_ip) == (subnet_mask & ip->ip_dst))
+ arp_entry = lookup_mac_addr(ip->ip_dst);
+ // if not then we need to know the router's IP address
+ else {
+ ip_dst = router_ip;
+ arp_entry = lookup_mac_addr(router_ip);
+ }
+ if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0)
+ mac_addr = arp_entry->mac_addr;
+ }
+
+ // If we could not resolv the MAC address by our own...
+ if(!mac_addr) {
+ // send the ARP request
+ arp_send_request(fd, ip_dst);
+
+ // drop the current packet if there is already a ARP request pending
+ if(arp_entry)
+ return -2;
+
+ // take the next entry in the ARP table to prepare a the new ARP entry.
+ arp_entry = &arp_table[arp_producer];
+ arp_producer = (arp_producer+1)%ARP_ENTRIES;
+
+ // if ARP table is full then we must drop the oldes entry.
+ if(arp_consumer == arp_producer)
+ arp_consumer = (arp_consumer+1)%ARP_ENTRIES;
+
+ // store the packet to be send if the ARP reply is received
+ arp_entry->pkt_pending = 1;
+ arp_entry->ipv4_addr = ip_dst;
+ memset(arp_entry->mac_addr, 0, 6);
+ pending_pkt.ipv4_addr = ip_dst;
+ memset(pending_pkt.mac_addr, 0, 6);
+ fill_ethhdr (pending_pkt.eth_frame, htons(ETHERTYPE_IP),
+ get_mac_address(), null_mac_addr);
+ memcpy(&pending_pkt.eth_frame[sizeof(struct ethhdr)],
+ buffer, len);
+ pending_pkt.eth_len = len + sizeof(struct ethhdr);
+
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether(fd);
+ if (!arp_entry->eth_len)
+ break;
+ } while (get_timer() > 0);
+
+ return 0;
+ }
+
+ // Send the packet with the known MAC address
+ fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP),
+ get_mac_address(), mac_addr);
+ memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len);
+ return send_ether(fd, arp_entry->eth_frame, len + sizeof(struct ethhdr));
+}
+
+/**
+ * IPv4: Calculate UDP checksum. Places the result into the UDP-header.
+ * <p>
+ * Use this function after filling the UDP payload.
+ *
+ * @param ipv4_hdr Points to the place where IPv4-header starts.
+ */
+
+static void
+fill_udp_checksum(struct iphdr *ipv4_hdr)
+{
+ int i;
+ unsigned long checksum = 0;
+ struct iphdr ip_hdr;
+ char *ptr;
+ udp_hdr_t *udp_hdr;
+
+ udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1);
+ udp_hdr->uh_sum = 0;
+
+ memset(&ip_hdr, 0, sizeof(struct iphdr));
+ ip_hdr.ip_src = ipv4_hdr->ip_src;
+ ip_hdr.ip_dst = ipv4_hdr->ip_dst;
+ ip_hdr.ip_len = udp_hdr->uh_ulen;
+ ip_hdr.ip_p = ipv4_hdr->ip_p;
+
+ ptr = (char*) udp_hdr;
+ for (i = 0; i < udp_hdr->uh_ulen; i+=2)
+ checksum += *((uint16_t*) &ptr[i]);
+
+ ptr = (char*) &ip_hdr;
+ for (i = 0; i < sizeof(struct iphdr); i+=2)
+ checksum += *((uint16_t*) &ptr[i]);
+
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+ udp_hdr->uh_sum = ~checksum;
+
+ /* As per RFC 768, if the computed checksum is zero,
+ * it is transmitted as all ones (the equivalent in
+ * one's complement arithmetic).
+ */
+ if (udp_hdr->uh_sum == 0)
+ udp_hdr->uh_sum = ~udp_hdr->uh_sum;
+}
+
+/**
+ * IPv4: Calculates checksum for IP header.
+ *
+ * @param packet Points to the IP-header
+ * @param words Size of the packet in words incl. IP-header and data.
+ * @return Checksum
+ * @see iphdr
+ */
+static unsigned short
+checksum(unsigned short * packet, int words)
+{
+ unsigned long checksum;
+
+ for (checksum = 0; words > 0; words--)
+ checksum += *packet++;
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+
+ return ~checksum;
+}
+
+static arp_entry_t*
+lookup_mac_addr(uint32_t ipv4_addr)
+{
+ unsigned int i;
+
+ for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
+ if(arp_table[i].ipv4_addr == ipv4_addr)
+ return &arp_table[i];
+ }
+ return 0;
+}
+
+
+/**
+ * ARP: Sends an ARP-request package.
+ * For given IPv4 retrieves MAC via ARP (makes several attempts)
+ *
+ * @param fd socket fd
+ * @param dest_ip IP of the host which MAC should be obtained
+ */
+static void
+arp_send_request(int fd, uint32_t dest_ip)
+{
+ arp_entry_t *arp_entry = &arp_table[arp_producer];
+
+ memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
+ fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST,
+ get_mac_address(), own_ip, broadcast_mac, dest_ip);
+ fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
+ get_mac_address(), broadcast_mac);
+
+ send_ether(fd, arp_entry->eth_frame,
+ sizeof(struct ethhdr) + sizeof(struct arphdr));
+}
+
+/**
+ * ARP: Sends an ARP-reply package.
+ * This package is used to serve foreign requests (in case IP in
+ * foreign request matches our host IP).
+ *
+ * @param fd socket fd
+ * @param src_ip requester IP address (foreign IP)
+ * @param src_mac requester MAC address (foreign MAC)
+ */
+static void
+arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac)
+{
+ arp_entry_t *arp_entry = &arp_table[arp_producer];
+
+ memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
+ fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
+ get_mac_address(), src_mac);
+ fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY,
+ get_mac_address(), own_ip, src_mac, src_ip);
+
+ send_ether(fd, arp_entry->eth_frame,
+ sizeof(struct ethhdr) + sizeof(struct arphdr));
+}
+
+/**
+ * ARP: Creates ARP package. Places ARP-header in a packet and fills it
+ * with corresponding information.
+ * <p>
+ * Use this function with similar functions for other network layers
+ * (fill_ethhdr).
+ *
+ * @param packet Points to the place where ARP-header must be placed.
+ * @param opcode Identifies is it request (ARP_REQUEST)
+ * or reply (ARP_REPLY) package.
+ * @param src_mac sender MAC address
+ * @param src_ip sender IP address
+ * @param dest_mac receiver MAC address
+ * @param dest_ip receiver IP address
+ * @see arphdr
+ * @see fill_ethhdr
+ */
+static void
+fill_arphdr(uint8_t * packet, uint8_t opcode,
+ const uint8_t * src_mac, uint32_t src_ip,
+ const uint8_t * dest_mac, uint32_t dest_ip)
+{
+ struct arphdr * arph = (struct arphdr *) packet;
+
+ arph -> hw_type = htons(1);
+ arph -> proto_type = htons(ETHERTYPE_IP);
+ arph -> hw_len = 6;
+ arph -> proto_len = 4;
+ arph -> opcode = htons(opcode);
+
+ memcpy(arph->src_mac, src_mac, 6);
+ arph->src_ip = htonl(src_ip);
+ memcpy(arph->dest_mac, dest_mac, 6);
+ arph->dest_ip = htonl(dest_ip);
+}
+
+/**
+ * ARP: Handles ARP-messages according to Receive-handle diagram.
+ * Updates arp_table for outstanding ARP requests (see arp_getmac).
+ *
+ * @param fd socket fd
+ * @param packet ARP-packet to be handled
+ * @param packetsize length of the packet
+ * @return ZERO - packet handled successfully;
+ * NON ZERO - packet was not handled (e.g. bad format)
+ * @see arp_getmac
+ * @see receive_ether
+ * @see arphdr
+ */
+int8_t
+handle_arp(int fd, uint8_t * packet, int32_t packetsize)
+{
+ struct arphdr * arph = (struct arphdr *) packet;
+
+ if (packetsize < sizeof(struct arphdr))
+ return -1; // Packet is too small
+
+ if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP))
+ return -1; // Unknown hardware or unsupported protocol
+
+ if (arph -> dest_ip != htonl(own_ip))
+ return -1; // receiver IP doesn't match our IP
+
+ switch(htons(arph -> opcode)) {
+ case ARP_REQUEST:
+ // foreign request
+ if(own_ip != 0)
+ arp_send_reply(fd, htonl(arph->src_ip), arph -> src_mac);
+ return 0; // no error
+ case ARP_REPLY: {
+ unsigned int i;
+ // if it is not for us -> return immediately
+ if(memcmp(get_mac_address(), arph->dest_mac, 6)) {
+ return 0; // no error
+ }
+
+ if(arph->src_ip == 0) {
+ // we are not interested for a MAC address if
+ // the IPv4 address is 0.0.0.0 or ff.ff.ff.ff
+ return -1;
+ }
+
+ // now let's find the corresponding entry in the ARP table
+
+ for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
+ if(arp_table[i].ipv4_addr == arph->src_ip)
+ break;
+ }
+ if(i == arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr, 6) != 0) {
+ // we have not asked to resolve this IPv4 address !
+ return -1;
+ }
+
+ memcpy(arp_table[i].mac_addr, arph->src_mac, 6);
+
+ // do we have something to send
+ if (arp_table[i].pkt_pending) {
+ struct ethhdr * ethh = (struct ethhdr *) pending_pkt.eth_frame;
+ memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6);
+
+ send_ether(fd, pending_pkt.eth_frame, pending_pkt.eth_len);
+ pending_pkt.pkt_pending = 0;
+ arp_table[i].eth_len = 0;
+ }
+ return 0; // no error
+ }
+ default:
+ break;
+ }
+ return -1; // Invalid message type
+}
+
+/**
+ * ICMP: Send an ICMP Echo request to destination IPv4 address.
+ * This function does also set a global variable to the
+ * destination IPv4 address. If there is an ICMP Echo Reply
+ * received later then the variable is set back to 0.
+ * In other words, reading a value of 0 form this variable
+ * means that an answer to the request has been arrived.
+ *
+ * @param fd socket descriptor
+ * @param _ping_dst_ip destination IPv4 address
+ */
+void
+ping_ipv4(int fd, uint32_t _ping_dst_ip)
+{
+ unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)];
+ struct icmphdr *icmp;
+
+ ping_dst_ip = _ping_dst_ip;
+
+ if(ping_dst_ip == 0)
+ return;
+
+ fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP,
+ 0, ping_dst_ip);
+ icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));
+ icmp->type = ICMP_ECHO_REQUEST;
+ icmp->code = 0;
+ icmp->checksum = 0;
+ icmp->options.echo.id = 0xd476;
+ icmp->options.echo.seq = 1;
+
+ memset(icmp->payload.data, '*', sizeof(icmp->payload.data));
+
+ icmp->checksum =
+ checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1);
+ send_ipv4(fd, packet, sizeof(struct iphdr) + sizeof(struct icmphdr));
+}
+
+/**
+ * ICMP: Return host IPv4 address that we are waiting for a
+ * ICMP Echo reply message. If this value is 0 then we have
+ * received an reply.
+ *
+ * @return ping_dst_ip host IPv4 address
+ */
+uint32_t
+pong_ipv4(void)
+{
+ return ping_dst_ip;
+}
+
+/**
+ * ICMP: Handles ICMP-packets according to Receive-handle diagram.
+ *
+ * @param fd socket fd
+ * @param icmp_packet ICMP-packet to be handled
+ * @param packetsize Length of the packet
+ * @return ZERO - packet handled successfully;
+ * NON ZERO - packet was not handled (e.g. bad format)
+ * @see handle_ipv4
+ */
+static int8_t
+handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize)
+{
+ struct icmphdr *icmp = (struct icmphdr *) packet;
+
+ switch(icmp->type) {
+ case ICMP_ECHO_REPLY:
+ if (icmp->options.echo.id != 0xd476)
+ return -1;
+ if (icmp->options.echo.seq != 1)
+ return -1;
+ if(ping_dst_ip != iph->ip_src
+ || ping_dst_ip == 0)
+ return -1;
+ ping_dst_ip = 0;
+ break;
+ case ICMP_DST_UNREACHABLE: {
+ // We've got Destination Unreachable msg
+ // Inform corresponding upper network layers
+ struct iphdr * bad_iph = (struct iphdr * ) &icmp->payload;
+
+ switch(bad_iph->ip_p) {
+ case IPTYPE_TCP:
+ handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize
+ - sizeof(struct icmphdr)
+ - sizeof(struct iphdr), icmp->code);
+ break;
+ case IPTYPE_UDP:
+ handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize
+ - sizeof(struct icmphdr)
+ - sizeof(struct iphdr), icmp->code);
+ break;
+ }
+ break;
+ }
+ case ICMP_SRC_QUENCH:
+ break;
+ case ICMP_REDIRECT:
+ break;
+ case ICMP_ECHO_REQUEST: {
+ // We've got an Echo Request - answer with Echo Replay msg
+ unsigned char reply_packet[sizeof(struct iphdr) + packetsize];
+ struct icmphdr *reply_icmph;
+
+ fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize,
+ IPTYPE_ICMP, 0, iph->ip_src);
+
+ reply_icmph = (struct icmphdr *) &reply_packet[sizeof(struct iphdr)];
+ memcpy(reply_icmph, packet, packetsize);
+ reply_icmph -> type = ICMP_ECHO_REPLY;
+ reply_icmph -> checksum = 0;
+ reply_icmph->checksum = checksum((unsigned short *) reply_icmph,
+ sizeof(struct icmphdr) >> 1);
+
+ send_ipv4(fd, reply_packet, sizeof(struct iphdr) + packetsize);
+ break;
+ }
+ case ICMP_TIME_EXCEEDED:
+ break;
+ case ICMP_PARAMETER_PROBLEM:
+ break;
+ case ICMP_TIMESTAMP_REQUEST:
+ break;
+ case ICMP_TIMESTAMP_REPLY:
+ break;
+ case ICMP_INFORMATION_REQUEST:
+ break;
+ case ICMP_INFORMATION_REPLY:
+ break;
+ }
+ return 0;
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h
new file mode 100644
index 000000000..eb719f8b2
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+
+#ifndef _IPV4_H_
+#define _IPV4_H_
+
+#include <stdint.h>
+
+#define IPTYPE_ICMP 1
+
+/** \struct iphdr
+ * A header for IP-packets.
+ * For more information see RFC 791.
+ */
+struct iphdr {
+ uint8_t ip_hlv; /**< Header length and version of the header */
+ uint8_t ip_tos; /**< Type of Service */
+ uint16_t ip_len; /**< Length in octets, inlc. this header and data */
+ uint16_t ip_id; /**< ID is used to aid in assembling framents */
+ uint16_t ip_off; /**< Info about fragmentation (control, offset) */
+ uint8_t ip_ttl; /**< Time to Live */
+ uint8_t ip_p; /**< Next level protocol type */
+ uint16_t ip_sum; /**< Header checksum */
+ uint32_t ip_src; /**< Source IP address */
+ uint32_t ip_dst; /**< Destination IP address */
+};
+typedef struct iphdr ipv4_hdr_t;
+
+/* ICMP Error Codes */
+#define ICMP_NET_UNREACHABLE 0
+#define ICMP_HOST_UNREACHABLE 1
+#define ICMP_PROTOCOL_UNREACHABLE 2
+#define ICMP_PORT_UNREACHABLE 3
+#define ICMP_FRAGMENTATION_NEEDED 4
+#define ICMP_SOURCE_ROUTE_FAILED 5
+
+/** \struct arphdr
+ * A header for ARP-messages, retains info about HW and proto addresses.
+ * For more information see RFC 826.
+ */
+struct arphdr {
+ uint16_t hw_type; /**< HW address space (1 for Ethernet) */
+ uint16_t proto_type; /**< Protocol address space */
+ uint8_t hw_len; /**< Byte length of each HW address */
+ uint8_t proto_len; /**< Byte length of each proto address */
+ uint16_t opcode; /**< Identifies is it request (1) or reply (2) */
+ uint8_t src_mac[6]; /**< HW address of sender of this packet */
+ uint32_t src_ip; /**< Proto address of sender of this packet */
+ uint8_t dest_mac[6]; /**< HW address of target of this packet */
+ uint32_t dest_ip; /**< Proto address of target of this packet */
+} __attribute((packed));
+
+/*>>>>>>>>>>>>> Initialization of the IPv4 network layer. <<<<<<<<<<<<<*/
+extern void set_ipv4_address(uint32_t own_ip);
+extern uint32_t get_ipv4_address(void);
+extern void set_ipv4_multicast(uint32_t multicast_ip);
+extern uint32_t get_ipv4_multicast(void);
+extern void set_ipv4_router(uint32_t router_ip);
+extern uint32_t get_ipv4_router(void);
+extern void set_ipv4_netmask(uint32_t subnet_mask);
+extern uint32_t get_ipv4_netmask(void);
+
+extern int (*send_ip) (int fd, void *, int);
+
+/* fills ip header */
+extern void fill_iphdr(uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst);
+
+/* Send a IPv4 packet. Adding the Ethernet-Header and resolving the
+ * MAC address is done transparent in the background if necessary.
+ */
+extern int send_ipv4(int fd, void* buffer, int len);
+
+/* Sends an ICMP Echo request to destination IPv4 address */
+extern void ping_ipv4(int fd, uint32_t _ping_dst_ip);
+
+/* Returns host IPv4 address that we are waiting for a response */
+extern uint32_t pong_ipv4(void);
+
+/* Handles IPv4-packets that are detected by receive_ether. */
+extern int8_t handle_ipv4(int fd, uint8_t * packet, int32_t packetsize);
+
+/* Handles ARP-packets that are detected by receive_ether. */
+extern int8_t handle_arp(int fd, uint8_t * packet, int32_t packetsize);
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c
new file mode 100644
index 000000000..0cb0a2e7b
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c
@@ -0,0 +1,768 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+#include <netlib/icmpv6.h>
+#include <netlib/ndp.h>
+#include <netlib/udp.h>
+
+#undef IPV6_DEBUG
+//#define IPV6_DEBUG
+#ifdef IPV6_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while (0)
+#else
+#define dprintf(_x ...)
+#endif
+
+/****************************** PROTOTYPES *******************************/
+int8_t ip6addr_add (struct ip6addr_list_entry *new_address);
+static void ipv6_init(int fd);
+static int ip6_is_multicast (ip6_addr_t * ip);
+
+/****************************** LOCAL VARIABLES **************************/
+
+/* Own IPv6 address */
+static struct ip6addr_list_entry *own_ip6;
+
+/* Null IPv6 address */
+static ip6_addr_t null_ip6;
+
+/* helper variables */
+static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+
+/****************************** IMPLEMENTATION ***************************/
+
+/**
+ * IPv6: Set the own IPv6 address.
+ *
+ * @param fd Socket descriptor
+ * @param _own_ip client IPv6 address (e.g. ::1)
+ */
+void
+set_ipv6_address (int fd, ip6_addr_t *_own_ip6)
+{
+ own_ip6 = malloc (sizeof(struct ip6addr_list_entry));
+
+ /* If no address was passed as a parameter generate a link-local
+ * address from our MAC address.*/
+ if (_own_ip6 == NULL)
+ memcpy(&(own_ip6->addr.addr),
+ ip6_create_ll_address(get_mac_address()),
+ IPV6_ADDR_LENGTH);
+ else
+ memcpy (&(own_ip6->addr.addr), _own_ip6, 16);
+
+ /* Add to our list of IPv6 addresses */
+ ip6addr_add (own_ip6);
+
+ ipv6_init(fd);
+}
+
+/**
+ * IPv6: Get pointer to own IPv6 address.
+ *
+ * @return pointer to client IPv6 address (e.g. ::1)
+ */
+ip6_addr_t *
+get_ipv6_address (void)
+{
+ return (ip6_addr_t *) &(own_ip6->addr);
+}
+
+/**
+ * IPv6: Search for IPv6 address in list
+ *
+ * @return 0 - IPv6 address is not in list
+ * 1 - IPv6 address is in list
+ */
+static int8_t
+find_ip6addr (ip6_addr_t *ip)
+{
+ struct ip6addr_list_entry *n = NULL;
+
+ if (ip == NULL)
+ return 0;
+
+ for (n = first_ip6; n != NULL ; n=n->next)
+ if (ip6_cmp (&(n->addr), ip))
+ return 1; /* IPv6 address is in our list*/
+
+ return 0; /* not one of our IPv6 addresses*/
+}
+
+/**
+ * NET: Handles IPv6-packets
+ *
+ * @param fd - Socket descriptor
+ * @param ip6_packet - Pointer to IPv6 header
+ * @param packetsize - Size of Ipv6 packet
+ * @return ERROR - -1 if packet is too small or unknown protocol
+ * return value of handle_udp
+ *
+ * @see handle_udp
+ * @see ip6hdr
+ */
+int8_t
+handle_ipv6 (int fd, uint8_t * ip6_packet, int32_t packetsize)
+{
+
+ struct ip6hdr *ip6 = NULL;
+ ip6 = (struct ip6hdr *) ip6_packet;
+
+ /* Only handle packets which are for us */
+ if (! find_ip6addr(&(ip6->dst)))
+ return -1;
+
+ if (packetsize < sizeof(struct ip6hdr))
+ return -1; // packet is too small
+
+ switch (ip6->nh) {
+ case IPTYPE_UDP:
+ return handle_udp (fd, ip6_packet + sizeof (struct ip6hdr),
+ ip6->pl);
+ case IPTYPE_ICMPV6:
+ return handle_icmpv6 (fd, (struct ethhdr *) ip6_packet - sizeof(struct ethhdr),
+ ip6_packet);
+ }
+
+ return -1; // unknown protocol
+}
+
+ /**
+ * NET: Creates IPv6-packet. Places IPv6-header in a packet and fills it
+ * with corresponding information.
+ * <p>
+ * Use this function with similar functions for other network layers
+ * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr).
+ *
+ * @param packet Points to the place where IPv6-header must be placed.
+ * @param packetsize Size of payload (i.e. excluding ethhdr and ip6hdr)
+ * @param ip_proto Type of the next level protocol (e.g. UDP).
+ * @param ip6_src Sender IPv6 address
+ * @param ip6_dst Receiver IPv6 address
+ * @see ip6hdr
+ * @see fill_iphdr
+ * @see fill_ethhdr
+ * @see fill_udphdr
+ * @see fill_dnshdr
+ * @see fill_btphdr
+ */
+void
+fill_ip6hdr (uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst)
+{
+
+ struct ip6hdr * ip6h = (struct ip6hdr *) packet;
+
+ ip6h->ver_tc_fl = 6 << 28; // set version to 6
+ ip6h->pl = packetsize; // IPv6 payload size
+ ip6h->nh = ip_proto;
+ ip6h->hl = 255;
+ memcpy (&(ip6h->src), ip6_src, IPV6_ADDR_LENGTH);
+ memcpy (&(ip6h->dst), ip6_dst, IPV6_ADDR_LENGTH);
+}
+
+/**
+ * NET: For a given MAC calculates EUI64-Identifier.
+ * See RFC 4291 "IP Version 6 Addressing Architecture"
+ *
+ */
+uint64_t
+mac2eui64 (const uint8_t *mac)
+{
+ uint8_t eui64id[8];
+ uint64_t retid;
+
+ memcpy (eui64id, mac, 3);
+ memcpy (eui64id + 5, mac + 3, 3);
+ eui64id[3] = 0xff;
+ eui64id[4] = 0xfe;
+
+ memcpy(&retid, eui64id, 8);
+ return retid;
+}
+
+/**
+ * NET: create link-local IPv6 address
+ *
+ * @param own_mac MAC of NIC
+ * @return ll_addr pointer to newly created link-local address
+ */
+ip6_addr_t *
+ip6_create_ll_address (const uint8_t *own_mac)
+{
+ ip6_addr_t *ll_addr;
+
+ ll_addr = malloc (sizeof (struct ip6addr_list_entry));
+ memset (ll_addr, 0, IPV6_ADDR_LENGTH);
+ ll_addr->part.prefix |= IPV6_LL_PREFIX;
+ ll_addr->part.interface_id |= mac2eui64((uint8_t *) own_mac);
+
+ return ll_addr;
+}
+
+/*
+ * NET: check if we already have an address with the same prefix.
+ * @param struct ip6_addr_list_entry *ip6
+ * @return true or false
+ */
+int8_t
+unknown_prefix (ip6_addr_t *ip)
+{
+ struct ip6addr_list_entry *node;
+
+ for( node = first_ip6; node != NULL; node=node->next )
+ if( node->addr.part.prefix == ip->part.prefix )
+ return 0; /* address is one of ours */
+
+ return 1; /* prefix not yet in our list */
+}
+
+/*
+ * NET: Create empty element for prefix list and return a pointer to it;
+ * @return NULL - malloc failed
+ * ! NULL - pointer to new prefix_info
+ */
+struct prefix_info *
+ip6_create_prefix_info ()
+{
+ struct prefix_info *prfx_info;
+
+ prfx_info = malloc (sizeof(struct prefix_info));
+ if (!prfx_info)
+ return NULL;
+
+ return prfx_info;
+}
+
+/*
+ * NET: create a new IPv6 address with a given network prefix
+ * and add it to our IPv6 address list
+ *
+ * @param ip6_addr prefix (as received in RA)
+ * @return NULL - pointer to new ip6addr_list entry
+ */
+void *
+ip6_prefix2addr (ip6_addr_t prefix)
+{
+ struct ip6addr_list_entry *new_address;
+ uint64_t interface_id;
+
+ new_address = malloc (sizeof(struct ip6addr_list_entry));
+ if( !new_address )
+ return NULL;
+
+ /* fill new addr struct */
+ /* extract prefix from Router Advertisement */
+ memcpy (&(new_address->addr.part.prefix), &prefix, 8 );
+
+ /* interface id is generated from MAC address */
+ interface_id = mac2eui64 (get_mac_address());
+ memcpy (&(new_address->addr.part.interface_id), &interface_id, 8);
+
+ return new_address;
+}
+
+/**
+ * NET: add new IPv6 adress to list
+ *
+ * @param ip6_addr *new_address
+ * @return 0 - passed pointer = NULL;
+ * 1 - ok
+ */
+int8_t
+ip6addr_add (struct ip6addr_list_entry *new_address)
+{
+ struct ip6addr_list_entry *solicited_node;
+
+
+ if (new_address == NULL)
+ return 0;
+
+ /* Don't add the same address twice */
+ if (find_ip6addr (&(new_address->addr)))
+ return 0;
+
+ /* If address is a unicast address, we also have to process packets
+ * for its solicited-node multicast address.
+ * See RFC 2373 - IP Version 6 Adressing Architecture */
+ if (! ip6_is_multicast(&(new_address->addr))) {
+
+
+ solicited_node = malloc(sizeof(struct ip6addr_list_entry));
+ if (! solicited_node)
+ return 0;
+
+ solicited_node->addr.part.prefix = IPV6_SOLIC_NODE_PREFIX;
+ solicited_node->addr.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID;
+ solicited_node->addr.addr[13] = new_address->addr.addr[13];
+ solicited_node->addr.addr[14] = new_address->addr.addr[14];
+ solicited_node->addr.addr[15] = new_address->addr.addr[15];
+ ip6addr_add (solicited_node);
+ }
+
+ if (NULL == first_ip6)
+ first_ip6 = new_address;
+ last_ip6->next = new_address;
+ last_ip6 = new_address;
+ last_ip6->next = NULL;
+
+ return 1; /* no error */
+}
+
+/**
+ * NET: Initialize IPv6
+ *
+ * @param fd socket fd
+ */
+static void
+ipv6_init (int fd)
+{
+ int i = 0;
+
+ send_ip = &send_ipv6;
+
+ /* Address configuration parameters */
+ ip6_state.managed_mode = 0;
+
+ /* Null IPv6 address */
+ null_ip6.part.prefix = 0;
+ null_ip6.part.interface_id = 0;
+
+ /* Multicast addresses */
+ all_nodes_ll.addr.part.prefix = 0xff02000000000000;
+ all_nodes_ll.addr.part.interface_id = 1;
+ all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL;
+ all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL;
+ all_routers_ll.addr.part.prefix = 0xff02000000000000;
+ all_routers_ll.addr.part.interface_id = 2;
+
+ ip6addr_add(&all_nodes_ll);
+ /* ... */
+
+ /* Router list */
+ first_router = NULL;
+ last_router = first_router;
+
+ /* Init Neighbour cache */
+ first_neighbor = NULL;
+ last_neighbor = first_neighbor;
+
+ send_router_solicitation (fd);
+ for(i=0; i < 4 && !is_ra_received(); i++) {
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether(fd);
+ if (is_ra_received())
+ break;
+ } while (get_timer() > 0);
+ }
+}
+
+/**
+ * NET: compare IPv6 adresses
+ *
+ * @param ip6_addr ip_1
+ * @param ip6_addr ip_2
+ */
+int8_t
+ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2)
+{
+ return ((int8_t) !memcmp( &(ip_1->addr[0]), &(ip_2->addr[0]),
+ IPV6_ADDR_LENGTH ));
+}
+
+/**
+ * NET: Calculate checksum over IPv6 header and upper-layer protocol
+ * (e.g. UDP or ICMPv6)
+ *
+ * @param *ip - pointer to IPv6 address
+ * @return true or false
+ */
+int
+ip6_is_multicast (ip6_addr_t * ip)
+{
+ uint8_t mc = 0xFF;
+ return ! memcmp(&ip->addr[0], &mc, 1);
+}
+
+/**
+ * NET: Generate multicast MAC address from IPv6 address
+ * (e.g. UDP or ICMPv6)
+ *
+ * @param *ip - pointer to IPv6 address
+ * @return pointer to Multicast MAC address
+ */
+static uint8_t *
+ip6_to_multicast_mac (ip6_addr_t * ip)
+{
+ uint8_t *mc_mac;
+
+ mc_mac = malloc(ETH_ALEN);
+ if (!mc_mac)
+ return NULL;
+
+ mc_mac[0] = 0x33;
+ mc_mac[1] = 0x33;
+ memcpy (mc_mac+2, (uint8_t *) &(ip->addr)+12, 4);
+
+ return mc_mac;
+}
+
+/**
+ * NET: calculate checksum over IPv6 header and upper-layer protocol
+ * (e.g. UDP or ICMPv6)
+ *
+ * @param struct ip6hdr *ip6h - pointer to IPv6 header
+ * @param unsigned short *packet - pointer to header of upper-layer
+ * protocol
+ * @param int words - number of words (as in 2 bytes)
+ * starting from *packet
+ * @return checksum
+ */
+static unsigned short
+ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words)
+{
+ int i=0;
+ unsigned long checksum;
+ struct ip6hdr pseudo_ip6h;
+ unsigned short *pip6h;
+
+ memcpy (&pseudo_ip6h, ip6h, sizeof(struct ip6hdr));
+ pseudo_ip6h.hl = ip6h->nh;
+ pseudo_ip6h.ver_tc_fl = 0;
+ pseudo_ip6h.nh = 0;
+ pip6h = (unsigned short *) &pseudo_ip6h;
+
+ for (checksum = 0; words > 0; words--) {
+ checksum += *packet++;
+ i++;
+ }
+
+ for (i = 0; i < 20; i++) {
+ checksum += *pip6h++;
+ }
+
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+
+ return ~checksum;
+}
+
+/**
+ * NET: Handles IPv6-packets
+ *
+ * @param fd socket fd
+ * @param ip6_packet Pointer to IPv6 header in packet
+ * @param packetsize Size of IPv6 packet
+ * @return -1 == ERRROR
+ * return of handle_udp() or handle_icmp6()
+ *
+ * @see receive_ether
+ * @see ip6hdr
+ */
+int
+send_ipv6 (int fd, void* buffer, int len)
+{
+ struct neighbor *n;
+ struct ip6hdr *ip6h;
+ struct udphdr *udph;
+ struct icmp6hdr *icmp6h;
+ ip6_addr_t ip_dst;
+ uint8_t *mac_addr, mac[6];
+
+ mac_addr = mac;
+
+ ip6h = (struct ip6hdr *) buffer;
+ udph = (struct udphdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr));
+ icmp6h = (struct icmp6hdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr));
+
+ memcpy(&ip_dst, &ip6h->dst, 16);
+
+ if(len + sizeof(struct ethhdr) > 1500)
+ return -1;
+
+ if ( ip6_cmp (&ip6h->src, &null_ip6))
+ memcpy (&(ip6h->src), get_ipv6_address(), IPV6_ADDR_LENGTH);
+
+ if (ip6h->nh == 17) {//UDP
+ udph->uh_sum = ip6_checksum (ip6h, (unsigned short *) udph ,
+ ip6h->pl >> 1);
+ /* As per RFC 768, if the computed checksum is zero,
+ * it is transmitted as all ones (the equivalent in
+ * one's complement arithmetic).
+ */
+ if (udph->uh_sum == 0)
+ udph->uh_sum = ~udph->uh_sum;
+ }
+ else if (ip6h->nh == 0x3a) //ICMPv6
+ icmp6h->checksum = ip6_checksum (ip6h,
+ (unsigned short *) icmp6h,
+ ip6h->pl >> 1);
+
+ n = find_neighbor (&ip_dst);
+
+ // If packet is a neighbor solicitation
+ if (icmp6h->type == ICMPV6_NEIGHBOUR_SOLICITATION) {
+ mac_addr = ip6_to_multicast_mac (&ip_dst);
+ fill_ethhdr( buffer-sizeof(struct ethhdr), htons(ETHERTYPE_IPv6),
+ get_mac_address(),
+ mac_addr);
+ }
+
+ // If address is a multicast address, create a proper mac address
+ else if (ip6_is_multicast (&ip_dst)) {
+ mac_addr = ip6_to_multicast_mac (&ip_dst);
+ }
+ else {
+ // Check if the MAC address is already cached
+ if (n) {
+ if (memcmp(n->mac, null_mac, ETH_ALEN) != 0)
+ memcpy (mac_addr, &(n->mac), ETH_ALEN); /* found it */
+ } else {
+ mac_addr = null_mac;
+ n = malloc(sizeof(struct neighbor));
+ memcpy(&(n->ip.addr[0]), &ip_dst, 16);
+ n->status = NB_PROBE;
+ n->times_asked += 1;
+ neighbor_add(n);
+ }
+
+ if (! memcmp (mac_addr, &null_mac, 6)) {
+ if (n->eth_len == 0) {
+ send_neighbour_solicitation (fd, &ip_dst);
+
+ // Store the packet until we know the MAC address
+ memset(n->eth_frame, 0, 1500);
+ fill_ethhdr (n->eth_frame,
+ htons(ETHERTYPE_IPv6),
+ get_mac_address(),
+ mac_addr);
+ memcpy (&(n->eth_frame[sizeof(struct ethhdr)]),
+ buffer, len);
+ n->eth_len = len;
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether(fd);
+ } while (get_timer() > 0);
+ }
+ }
+ }
+
+ fill_ethhdr (n->eth_frame, htons(ETHERTYPE_IPv6), get_mac_address(),
+ mac_addr);
+ memcpy (&(n->eth_frame[sizeof(struct ethhdr)]), buffer, len);
+ return send_ether (fd, n->eth_frame, len + sizeof(struct ethhdr));
+}
+
+static int
+check_colons(const char *str)
+{
+ char *pch, *prv;
+ int col = 0;
+ int dcol = 0;
+
+ dprintf("str : %s\n",str);
+ pch = strchr(str, ':');
+ while(pch != NULL){
+ prv = pch;
+ pch = strchr(pch+1, ':');
+ if((pch-prv) != 1) {
+ col++;
+ } else {
+ col--; /* Its part of double colon */
+ dcol++;
+ }
+ }
+
+ dprintf("The number of col : %d \n",col);
+ dprintf("The number of dcol : %d \n",dcol);
+
+ if((dcol > 1) || /* Cannot have 2 "::" */
+ ((dcol == 1) && (col > 5)) || /* Too many ':'s */
+ ((dcol == 0) && (col != 7)) ) { /* Too few ':'s */
+ dprintf(" exiting for check_colons \n");
+ return 0;
+ }
+
+ return (col+dcol);
+}
+
+static int
+ipv6str_to_bytes(const char *str, char *ip)
+{
+ char block[5];
+ int res;
+ char *pos;
+ uint32_t cnt = 0, len;
+
+ dprintf("str : %s \n",str);
+
+ while (*str != 0) {
+ if (cnt > 15 || !isxdigit(*str)){
+ return 0;
+ }
+ if ((pos = strchr(str, ':')) != NULL) {
+ len = (int16_t) (pos - str);
+ dprintf("\t len is : %d \n",len);
+ if (len > 4)
+ return 0;
+ strncpy(block, str, len);
+ block[len] = 0;
+ dprintf("\t str : %s \n",str);
+ dprintf("\t block : %s \n",block);
+ str += len;
+ } else {
+ strncpy(block, str, 4);
+ block[4] = 0;
+ dprintf("\t str : %s \n",str);
+ dprintf("\t block : %s \n",block);
+ str += strlen(block);
+ }
+ res = strtol(block, NULL, 16);
+ dprintf("\t res : %x \n",res);
+ if ((res > 0xFFFF) || (res < 0))
+ return 0;
+ ip[cnt++] = (res & 0xFF00) >> 8;
+ ip[cnt++] = (res & 0x00FF);
+ if (*str == ':'){
+ str++;
+ }
+ }
+
+ dprintf("cnt : %d\n",cnt);
+ return cnt;
+}
+
+int str_to_ipv6(const char *str, uint8_t *ip)
+{
+ int i, k;
+ uint16_t len;
+ char *ptr;
+ char tmp[30], buf[16];
+
+ memset(ip,0,16);
+
+ if(!check_colons(str))
+ return 0;
+
+ if ((ptr = strstr(str, "::")) != NULL) {
+ /* Handle the ::1 IPv6 loopback */
+ if(!strcmp(str,"::1")) {
+ ip[15] = 1;
+ return 16;
+ }
+ len = (ptr-str);
+ dprintf(" len : %d \n",len);
+ if (len >= sizeof(tmp))
+ return 0;
+ strncpy(tmp, str, len);
+ tmp[len] = 0;
+ ptr += 2;
+
+ i = ipv6str_to_bytes(ptr, buf);
+ if(i == 0)
+ return i;
+
+ #if defined(ARGS_DEBUG)
+ int j;
+ dprintf("=========== bottom part i : %d \n",i);
+ for(j=0; j<i; j++)
+ dprintf("%02x \t",buf[j]);
+ #endif
+
+ /* Copy the bottom part i.e bytes following "::" */
+ memcpy(ip+(16-i), buf, i);
+
+ k = ipv6str_to_bytes(tmp, buf);
+ if(k == 0)
+ return k;
+
+ #if defined(ARGS_DEBUG)
+ dprintf("=========== top part k : %d \n",k);
+ for(j=0; j<k; j++)
+ printf("%02x \t",buf[j]);
+ #endif
+
+ /* Copy the top part i.e bytes before "::" */
+ memcpy(ip, buf, k);
+ #if defined(ARGS_DEBUG)
+ dprintf("\n");
+ for(j=0; j<16; j++)
+ dprintf("%02x \t",ip[j]);
+ #endif
+
+ } else {
+ i = ipv6str_to_bytes(str, (char *)ip);
+ }
+ return i;
+}
+
+void ipv6_to_str(const uint8_t *ip, char *str)
+{
+ int i, len;
+ uint8_t byte_even, byte_odd;
+ char *consec_zero, *strptr;
+
+ *str = 0;
+ for (i = 0; i < 16; i+=2) {
+ byte_even = ip[i];
+ byte_odd = ip[i+1];
+ if (byte_even)
+ sprintf(str, "%s%x%02x", str, byte_even, byte_odd);
+ else if (byte_odd)
+ sprintf(str, "%s%x", str, byte_odd);
+ else
+ strcat(str, "0");
+ if (i != 14)
+ strcat(str, ":");
+ }
+ strptr = str;
+ do {
+ consec_zero = strstr(strptr, "0:0:");
+ if (consec_zero) {
+ len = consec_zero - strptr;
+ if (!len)
+ break;
+ else if (strptr[len-1] == ':')
+ break;
+ else
+ strptr = consec_zero + 2;
+ }
+ } while (consec_zero);
+ if (consec_zero) {
+ len = consec_zero - str;
+ str[len] = 0;
+ if (len)
+ strcat(str, ":");
+ else
+ strcat(str, "::");
+ strptr = consec_zero + 4;
+ while (*strptr) {
+ if (!strncmp(strptr, "0:", 2))
+ strptr += 2;
+ else
+ break;
+ }
+ strcat(str, strptr);
+ if (!strcmp(str, "::0"))
+ strcpy(str, "::");
+ }
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h
new file mode 100644
index 000000000..b496364f3
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h
@@ -0,0 +1,196 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#ifndef _IPV6_H_
+#define _IPV6_H_
+
+#include <stdint.h>
+#include <netlib/ethernet.h>
+
+#define __IPV6_DEBUG__
+
+#ifdef __IPV6_DEBUG__
+#define IPV6_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__); } while (0)
+#else
+#define IPV6_DEBUG_PRINT(format, ...)
+#endif
+
+#define IPV6_ADDR_LENGTH 16 /* Size of IPv6 adress in bytes */
+#define IPV6_LL_PREFIX 0xFE80000000000000ULL
+#define IPV6_SOLIC_NODE_PREFIX 0xFF02000000000000ULL
+#define IPV6_SOLIC_NODE_IFACE_ID 0x00000001FF000000ULL
+
+/**
+ * An IPv6 Address
+ */
+typedef union {
+ uint8_t addr[IPV6_ADDR_LENGTH];
+ struct {
+ uint64_t prefix;
+ uint64_t interface_id;
+ } part;
+} ip6_addr_t;
+
+typedef struct {
+ uint8_t type;
+ uint8_t pad[7];
+ union {
+ ip6_addr_t v6;
+ char v4[4];
+ } addr;
+} netaddr_t;
+
+/** \struct prefix_info
+ *
+ * List of Prefixes we have adresses from
+ * Used for internal purposes, information derived from prefix option
+ * in Router Advertisements
+ * See RFC 4861 section 4.6.2
+ */
+struct prefix_info {
+ uint64_t prefix;
+ uint8_t on_link:1, /* When set prefix can be used for on-link
+ * determination */
+ autoconf:1, /* Prefix can be used for stateless address
+ * configuration */
+ reserved1:6;
+ uint32_t valid_lifetime; /* Time until prefix expires */
+ uint32_t preferred_lifetime; /* Time until prefix becomes deprecated */
+ uint32_t start_time; /* Time when received */
+ uint32_t reserved2;
+ struct prefix_info *next;
+};
+
+
+/* List of IPv6 addresses */
+struct ip6addr_list_entry {
+ ip6_addr_t addr;
+ struct prefix_info prfx_info;
+ struct ip6addr_list_entry *next;
+};
+
+/** \struct ip6hdr
+ * A header for IPv6 packets.
+ * For more information see RFC 2460
+ */
+struct ip6hdr {
+ uint32_t ver_tc_fl; /**< Version, Traffic class, Flow label */
+ uint16_t pl; /**< Payload length */
+ uint8_t nh; /**< Next header */
+ uint8_t hl; /**< Hop limit */
+ ip6_addr_t src; /**< IPv6 source address */
+ ip6_addr_t dst; /**< IPv6 destination address */
+} __attribute((packed));
+
+/** \struct packeth
+ * Struct with pointers to headers within a packet
+ */
+struct packeth {
+ struct ethhdr *ethh;
+ struct ip6hdr *ip6h;
+ struct icmp6hdr *icmp6h;
+ struct udphdr *udph;
+ /* ... */
+};
+
+/** \struct parseip6_state
+ * Stores information about state of IPv6 address parser
+ */
+struct parseip6_state {
+ char *lookahead;
+ char *ptr;
+ const char *addr;
+ int state;
+ int s1ctr;
+ int s2ctr;
+ int blocknr;
+ int zeroblocks;
+ int i;
+ int done;
+ int errorcode;
+};
+
+/** \struct ip6_config
+ * Stores flags wheter we use Stateless- or Stateful Autoconfiguration or DHCPv6
+ */
+struct ip6_config {
+ uint8_t managed_mode:1,
+ other_config:1,
+ reserved:6;
+} ip6_state;
+
+/******************** VARIABLES **********************************************/
+/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
+extern int (*send_ip) (int fd, void *, int);
+
+/* IPv6 link-local multicast addresses */
+struct ip6addr_list_entry all_routers_ll; // Routers
+struct ip6addr_list_entry all_dhcpv6_ll; // DHCPv6 servers
+struct ip6addr_list_entry all_nodes_ll; // All IPv6 nodes
+
+/* List of Ipv6 Addresses */
+struct ip6addr_list_entry *first_ip6;
+struct ip6addr_list_entry *last_ip6;
+
+/* Neighbor cache */
+struct neighbor *first_neighbor;
+struct neighbor *last_neighbor;
+
+/* Router list */
+struct router *first_router;
+struct router *last_router;
+
+/******************** FUNCTIONS *********************************************/
+/* Handles IPv6-packets that are detected by receive_ether. */
+int8_t handle_ipv6(int fd, uint8_t * ip6_packet, int32_t packetsize);
+
+/* Fill IPv6 header */
+void fill_ip6hdr(uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst);
+
+/* Set own IPv6 address */
+void set_ipv6_address(int fd, ip6_addr_t *own_ip6);
+
+/* Get own IPv6 address */
+ip6_addr_t *get_ipv6_address(void);
+
+/* Create link-local address from a given Mac Address */
+ip6_addr_t * ip6_create_ll_address (const uint8_t *own_mac);
+
+/* For a given MAC calculates EUI64-Identifier.*/
+uint64_t mac2eui64 (const uint8_t *mac);
+
+/* Create empty element for prefix list and return a pointer to it */
+struct prefix_info * ip6_create_prefix_info(void);
+
+/* Create a new IPv6 address with a given network prefix
+ * and add it to our IPv6 address list */
+void * ip6_prefix2addr (ip6_addr_t prefix);
+
+/* Compare IPv6 adresses */
+int8_t ip6_cmp( ip6_addr_t *ip_1, ip6_addr_t *ip_2 );
+
+/* Check if prefix is already in our list */
+int8_t unknown_prefix (ip6_addr_t *ip);
+
+/* Send IPv6 packet */
+int send_ipv6 (int fd, void* buffer, int len);
+
+/* Add IPv6 address to list */
+int8_t ip6addr_add (struct ip6addr_list_entry *new_address);
+
+/* Parse an IPv6 address */
+int parseip6(const char *addr, uint8_t *parsedaddr);
+int str_to_ipv6(const char *str, uint8_t *ip);
+void ipv6_to_str(const uint8_t *ip, char *str);
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c
new file mode 100644
index 000000000..ed9d61f4a
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c
@@ -0,0 +1,147 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <netlib/ipv6.h>
+#include <netlib/icmpv6.h>
+#include <netlib/ndp.h>
+
+/*
+ * NET: add new router to list
+ * @param struct router nghb - new router
+ * @return true or false
+ */
+int8_t
+router_add (struct router *nghb )
+{
+ if (nghb == NULL)
+ return -1;
+
+ if (first_router == NULL) {
+ first_router= nghb;
+ last_router = first_router;
+ last_router->next = NULL;
+ } else {
+ last_router->next = nghb;
+ last_router = nghb;
+ last_router->next = NULL;
+ }
+ return 1; /* no error */
+}
+
+/*
+ * NET: create a new router
+ * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghSlct)
+ * @param struct packeth - pointers to headers in packet
+ * @return pointer to new router
+ */
+void *
+router_create (uint8_t *mac, ip6_addr_t *ip)
+{
+ struct router *new_router;
+
+ new_router = malloc (sizeof(struct router));
+ if( !new_router) {
+ return 0;
+ }
+ memset (new_router, 0, sizeof(struct router));
+
+ /* fill neighbor struct */
+ memcpy (new_router->mac, mac, 6);
+ memcpy (&(new_router->ip.addr[0]), &(ip->addr[0]), IPV6_ADDR_LENGTH);
+
+ return new_router;
+}
+
+struct router *
+find_router( ip6_addr_t *ip )
+{
+ struct router *n = NULL;
+
+ for (n = first_router; n != NULL ; n=n->next)
+ if (ip6_cmp (&(n->ip), ip))
+ return n; /* router is already in list*/
+
+ return NULL; /* router is unknown */
+}
+
+/*
+ * NET: add new neighbor to list
+ * @param struct neighbor nghb - new neighbor
+ * @return true or false
+ */
+int8_t
+neighbor_add (struct neighbor *nghb)
+{
+ if (nghb == NULL)
+ return -1;
+
+ if (first_neighbor == NULL) {
+ first_neighbor = nghb;
+ last_neighbor = first_neighbor;
+ last_neighbor->next = NULL;
+ } else {
+ last_neighbor->next = nghb;
+ last_neighbor = nghb;
+ last_neighbor->next = NULL;
+ }
+
+ return 1; /* no error */
+}
+
+/*
+ * NET: create a new neighbor
+ * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghSlct)
+ * @param struct packeth - pointers to headers in packet
+ * @return pointer - pointer to new neighbor
+ * NULL - malloc failed
+ */
+void *
+neighbor_create (uint8_t *packet, struct packeth *headers)
+{
+ struct neighbor *new_neighbor;
+
+ new_neighbor = malloc (sizeof(struct neighbor));
+ if( !new_neighbor )
+ return NULL;
+
+ /* fill neighbor struct */
+ memcpy (&(new_neighbor->mac),
+ &(headers->ethh->src_mac[0]), 6);
+ memcpy (&(new_neighbor->ip.addr), &(headers->ip6h->src), IPV6_ADDR_LENGTH);
+ new_neighbor->status = NB_INCOMPLETE;
+
+ return new_neighbor;
+}
+
+/**
+ * NET: Find neighbor with given IPv6 address in Neighbor Cache
+ *
+ * @param ip - Pointer to IPv6 address
+ * @return pointer - pointer to client IPv6 address (e.g. ::1)
+ * NULL - Neighbor not found
+ */
+struct neighbor *
+find_neighbor (ip6_addr_t *ip)
+{
+ struct neighbor *n = NULL;
+
+ for (n = first_neighbor; n != NULL ; n=n->next) {
+ if (ip6_cmp (&(n->ip), ip)) {
+ return n; /* neighbor is already in cache */
+ }
+ }
+
+ return NULL; /* neighbor is unknown */
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h
new file mode 100644
index 000000000..ee5235fe1
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * Copyright (c) 2013 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
+ *****************************************************************************/
+
+#ifndef _NDP_H_
+#define _NDP_H_
+
+#include <netlib/ipv6.h>
+
+#define __NDP_DEBUG__
+
+#ifdef __NDP_DEBUG__
+#define NDP_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__); } while (0)
+#else
+#define NDP_DEBUG_PRINT(format, ...)
+#endif
+
+#define ND_OPTION_SOURCE_LL_ADDR 1
+#define ND_OPTION_TARGET_LL_ADDR 2
+#define ND_OPTION_PREFIX_INFO 3
+#define ND_OPTION_REDIRECT_HDR 4
+#define ND_OPTION_MTU 5
+
+/* Default Router List */
+struct router {
+ uint8_t mac[6];
+ ip6_addr_t ip;
+ uint32_t lifetime;
+ uint32_t reachable_time;
+ uint32_t retrans_timer;
+ struct router *next;
+};
+
+/* Neighbor cache */
+struct neighbor {
+ uint8_t mac[6];
+ ip6_addr_t ip;
+ uint8_t is_router;
+ uint8_t status;
+ uint8_t times_asked;
+ /* ... */
+ struct neighbor *next;
+ uint8_t eth_frame[1500]; //FIXME
+ uint32_t eth_len;
+
+#define NB_INCOMPLETE 1
+#define NB_REACHABLE 2
+#define NB_STALE 3
+#define NB_DELAY 4
+#define NB_PROBE 5
+};
+
+/******************** FUNCTIONS *********************************************/
+int8_t neighbor_add (struct neighbor *);
+void * neighbor_create (uint8_t *packet, struct packeth *headers);
+struct neighbor * find_neighbor (ip6_addr_t *);
+
+int8_t router_add(struct router*);
+void * router_create(uint8_t *mac, ip6_addr_t *ip);
+struct router * find_router(ip6_addr_t *);
+
+#endif //_NDP_H_
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c
new file mode 100644
index 000000000..5511aa00a
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+
+#include <tcp.h>
+#include <sys/socket.h>
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+
+/**
+ * TCP: Handles TCP-packets according to Receive-handle diagram.
+ *
+ * @param tcp_packet TCP-packet to be handled
+ * @param packetsize Length of the packet
+ * @return ZERO - packet handled successfully;
+ * NON ZERO - packet was not handled (e.g. bad format)
+ */
+int8_t
+handle_tcp(uint8_t * tcp_packet, int32_t packetsize)
+{
+ return -1;
+}
+
+
+/**
+ * NET: This function handles situation when "Destination unreachable"
+ * ICMP-error occurs during sending TCP-packet.
+ *
+ * @param err_code Error Code (e.g. "Host unreachable")
+ * @param packet original TCP-packet
+ * @param packetsize length of the packet
+ * @see handle_icmp
+ */
+void
+handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code) {
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.h
new file mode 100644
index 000000000..375afd771
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+#ifndef _TCP_H
+#define _TCP_H
+
+#include <stdint.h>
+
+#define IPTYPE_TCP 6
+
+/* Handles TCP-packets that are detected by any network layer. */
+extern int8_t handle_tcp(uint8_t * udp_packet, int32_t packetsize);
+
+/* Handles TCP related ICMP-Dest.Unreachable packets that are detected by
+ * the network layers. */
+extern void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code);
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c
new file mode 100644
index 000000000..0a7c0ec63
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c
@@ -0,0 +1,597 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+#include <tftp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+
+#include <ethernet.h>
+#include <ipv4.h>
+#include <ipv6.h>
+#include <udp.h>
+
+//#define __DEBUG__
+
+#define MAX_BLOCKSIZE 1428
+#define BUFFER_LEN 256
+
+#define ENOTFOUND 1
+#define EACCESS 2
+#define EBADOP 4
+#define EBADID 5
+#define ENOUSER 7
+//#define EUNDEF 0
+//#define ENOSPACE 3
+//#define EEXISTS 6
+
+#define RRQ 1
+#define WRQ 2
+#define DATA 3
+#define ACK 4
+#define ERROR 5
+#define OACK 6
+
+/* Local variables */
+static unsigned char packet[BUFFER_LEN];
+static unsigned char *buffer = NULL;
+static unsigned short block = 0;
+static unsigned short blocksize;
+static char blocksize_str[6]; /* Blocksize string for read request */
+static int received_len = 0;
+static int retries = 0;
+static int huge_load;
+static int len;
+static int tftp_finished = 0;
+static int lost_packets = 0;
+static int tftp_errno = 0;
+static int ip_version = 0;
+static short port_number = -1;
+static tftp_err_t *tftp_err;
+static filename_ip_t *fn_ip;
+
+/**
+ * dump_package - Prints a package.
+ *
+ * @package: package which is to print
+ * @len: length of the package
+ */
+#ifdef __DEBUG__
+
+static void
+dump_package(unsigned char *buffer, unsigned int len)
+{
+ int i;
+
+ for (i = 1; i <= len; i++) {
+ printf("%02x%02x ", buffer[i - 1], buffer[i]);
+ i++;
+ if ((i % 16) == 0)
+ printf("\n");
+ }
+ printf("\n");
+}
+#endif
+
+/**
+ * send_rrq - Sends a read request package.
+ *
+ * @fd: Socket Descriptor
+ */
+static void
+send_rrq(int fd)
+{
+ int ip_len = 0;
+ int ip6_payload_len = 0;
+ unsigned short udp_len = 0;
+ unsigned char mode[] = "octet";
+ char *ptr = NULL;
+ struct iphdr *ip = NULL;
+ struct ip6hdr *ip6 = NULL;
+ struct udphdr *udph = NULL;
+ struct tftphdr *tftp = NULL;
+
+ memset(packet, 0, BUFFER_LEN);
+
+ if (4 == ip_version) {
+ ip = (struct iphdr *) packet;
+ udph = (struct udphdr *) (ip + 1);
+ ip_len = sizeof(struct iphdr) + sizeof(struct udphdr)
+ + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+ + strlen("blksize") + strlen(blocksize_str) + 2;
+ fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
+ fn_ip->server_ip);
+ }
+ else if (6 == ip_version) {
+ ip6 = (struct ip6hdr *) packet;
+ udph = (struct udphdr *) (ip6 + 1);
+ ip6_payload_len = sizeof(struct udphdr)
+ + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+ + strlen("blksize") + strlen(blocksize_str) + 2;
+ ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
+ fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
+ &(fn_ip->server_ip6));
+
+ }
+ udp_len = htons(sizeof(struct udphdr)
+ + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+ + strlen("blksize") + strlen(blocksize_str) + 2);
+ fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(69));
+
+ tftp = (struct tftphdr *) (udph + 1);
+ tftp->th_opcode = htons(RRQ);
+
+ ptr = (char *) &tftp->th_data;
+ memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1);
+
+ ptr += strlen((char *) fn_ip->filename) + 1;
+ memcpy(ptr, mode, strlen((char *) mode) + 1);
+
+ ptr += strlen((char *) mode) + 1;
+ memcpy(ptr, "blksize", strlen("blksize") + 1);
+
+ ptr += strlen("blksize") + 1;
+ memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1);
+
+ send_ip (fd, packet, ip_len);
+
+#ifdef __DEBUG__
+ printf("tftp RRQ with %d bytes transmitted.\n", ip_len);
+#endif
+ return;
+}
+
+/**
+ * send_ack - Sends a acknowlege package.
+ *
+ * @blckno: block number
+ * @dport: UDP destination port
+ */
+static void
+send_ack(int fd, int blckno, unsigned short dport)
+{
+ int ip_len = 0;
+ int ip6_payload_len = 0;
+ unsigned short udp_len = 0;
+ struct iphdr *ip = NULL;
+ struct ip6hdr *ip6 = NULL;
+ struct udphdr *udph = NULL;
+ struct tftphdr *tftp = NULL;
+
+ memset(packet, 0, BUFFER_LEN);
+
+ if (4 == ip_version) {
+ ip = (struct iphdr *) packet;
+ udph = (struct udphdr *) (ip + 1);
+ ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 4;
+ fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
+ fn_ip->server_ip);
+ }
+ else if (6 == ip_version) {
+ ip6 = (struct ip6hdr *) packet;
+ udph = (struct udphdr *) (ip6 + 1);
+ ip6_payload_len = sizeof(struct udphdr) + 4;
+ ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
+ ip6_payload_len;
+ fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
+ &(fn_ip->server_ip6));
+ }
+ udp_len = htons(sizeof(struct udphdr) + 4);
+ fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
+
+ tftp = (struct tftphdr *) (udph + 1);
+ tftp->th_opcode = htons(ACK);
+ tftp->th_data = htons(blckno);
+
+ send_ip(fd, packet, ip_len);
+
+#ifdef __DEBUG__
+ printf("tftp ACK %d bytes transmitted.\n", ip_len);
+#endif
+
+ return;
+}
+
+/**
+ * send_error - Sends an error package.
+ *
+ * @fd: Socket Descriptor
+ * @error_code: Used sub code for error packet
+ * @dport: UDP destination port
+ */
+static void
+send_error(int fd, int error_code, unsigned short dport)
+{
+ int ip_len = 0;
+ int ip6_payload_len = 0;
+ unsigned short udp_len = 0;
+ struct ip6hdr *ip6 = NULL;
+ struct iphdr *ip = NULL;
+ struct udphdr *udph = NULL;
+ struct tftphdr *tftp = NULL;
+
+ memset(packet, 0, BUFFER_LEN);
+
+ if (4 == ip_version) {
+ ip = (struct iphdr *) packet;
+ udph = (struct udphdr *) (ip + 1);
+ ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 5;
+ fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
+ fn_ip->server_ip);
+ }
+ else if (6 == ip_version) {
+ ip6 = (struct ip6hdr *) packet;
+ udph = (struct udphdr *) (ip6 + 1);
+ ip6_payload_len = sizeof(struct udphdr) + 5;
+ ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
+ ip6_payload_len;
+ fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
+ &(fn_ip->server_ip6));
+ }
+ udp_len = htons(sizeof(struct udphdr) + 5);
+ fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
+
+ tftp = (struct tftphdr *) (udph + 1);
+ tftp->th_opcode = htons(ERROR);
+ tftp->th_data = htons(error_code);
+ ((char *) &tftp->th_data)[2] = 0;
+
+ send_ip(fd, packet, ip_len);
+
+#ifdef __DEBUG__
+ printf("tftp ERROR %d bytes transmitted.\n", ip_len);
+#endif
+
+ return;
+}
+
+static void
+print_progress(int urgent, int received_bytes)
+{
+ static unsigned int i = 1;
+ static int first = -1;
+ static int last_bytes = 0;
+ char buffer[100];
+ char *ptr;
+
+ // 1MB steps or 0x400 times or urgent
+ if(((received_bytes - last_bytes) >> 20) > 0
+ || (i & 0x3FF) == 0 || urgent) {
+ if(!first) {
+ sprintf(buffer, "%d KBytes", (last_bytes >> 10));
+ for(ptr = buffer; *ptr != 0; ++ptr)
+ *ptr = '\b';
+ printf(buffer);
+ }
+ printf("%d KBytes", (received_bytes >> 10));
+ i = 1;
+ first = 0;
+ last_bytes = received_bytes;
+ }
+ ++i;
+}
+
+/**
+ * get_blksize tries to extract the blksize from the OACK package
+ * the TFTP returned. From RFC 1782
+ * The OACK packet has the following format:
+ *
+ * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
+ * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ *
+ * @param buffer the network packet
+ * @param len the length of the network packet
+ * @return the blocksize the server supports or 0 for error
+ */
+static int
+get_blksize(unsigned char *buffer, unsigned int len)
+{
+ unsigned char *orig = buffer;
+ /* skip all headers until tftp has been reached */
+ buffer += sizeof(struct udphdr);
+ /* skip opc */
+ buffer += 2;
+ while (buffer < orig + len) {
+ if (!memcmp(buffer, "blksize", strlen("blksize") + 1))
+ return (unsigned short) strtoul((char *) (buffer +
+ strlen("blksize") + 1),
+ (char **) NULL, 10);
+ else {
+ /* skip the option name */
+ buffer = (unsigned char *) strchr((char *) buffer, 0);
+ if (!buffer)
+ return 0;
+ buffer++;
+ /* skip the option value */
+ buffer = (unsigned char *) strchr((char *) buffer, 0);
+ if (!buffer)
+ return 0;
+ buffer++;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Handle incoming tftp packets after read request was sent
+ *
+ * this function also prints out some status characters
+ * \|-/ for each packet received
+ * A for an arp packet
+ * I for an ICMP packet
+ * #+* for different unexpected TFTP packets (not very good)
+ *
+ * @param fd socket descriptor
+ * @param packet points to the UDP header of the packet
+ * @param len the length of the network packet
+ * @return ZERO if packet was handled successfully
+ * ERRORCODE if error occurred
+ */
+int32_t
+handle_tftp(int fd, uint8_t *pkt, int32_t packetsize)
+{
+ struct udphdr *udph;
+ struct tftphdr *tftp;
+
+ /* buffer is only set if we are handling TFTP */
+ if (buffer == NULL )
+ return 0;
+
+#ifndef __DEBUG__
+ print_progress(0, received_len);
+#endif
+ udph = (struct udphdr *) pkt;
+ tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr));
+ set_timer(TICKS_SEC);
+
+#ifdef __DEBUG__
+ dump_package(pkt, packetsize);
+#endif
+
+ port_number = udph->uh_sport;
+ if (tftp->th_opcode == htons(OACK)) {
+ /* an OACK means that the server answers our blocksize request */
+ blocksize = get_blksize(pkt, packetsize);
+ if (!blocksize || blocksize > MAX_BLOCKSIZE) {
+ send_error(fd, 8, port_number);
+ tftp_errno = -8;
+ goto error;
+ }
+ send_ack(fd, 0, port_number);
+ } else if (tftp->th_opcode == htons(ACK)) {
+ /* an ACK means that the server did not answers
+ * our blocksize request, therefore we will set the blocksize
+ * to the default value of 512 */
+ blocksize = 512;
+ send_ack(fd, 0, port_number);
+ } else if ((unsigned char) tftp->th_opcode == ERROR) {
+#ifdef __DEBUG__
+ printf("tftp->th_opcode : %x\n", tftp->th_opcode);
+ printf("tftp->th_data : %x\n", tftp->th_data);
+#endif
+ switch ( (uint8_t) tftp->th_data) {
+ case ENOTFOUND:
+ tftp_errno = -3; // ERROR: file not found
+ break;
+ case EACCESS:
+ tftp_errno = -4; // ERROR: access violation
+ break;
+ case EBADOP:
+ tftp_errno = -5; // ERROR: illegal TFTP operation
+ break;
+ case EBADID:
+ tftp_errno = -6; // ERROR: unknown transfer ID
+ break;
+ case ENOUSER:
+ tftp_errno = -7; // ERROR: no such user
+ break;
+ default:
+ tftp_errno = -1; // ERROR: unknown error
+ }
+ goto error;
+ } else if (tftp->th_opcode == DATA) {
+ /* DATA PACKAGE */
+ if (block + 1 == tftp->th_data) {
+ ++block;
+ }
+ else if( block == 0xffff && huge_load != 0
+ && (tftp->th_data == 0 || tftp->th_data == 1) ) {
+ block = tftp->th_data;
+ }
+ else if (tftp->th_data == block) {
+#ifdef __DEBUG__
+ printf
+ ("\nTFTP: Received block %x, expected block was %x\n",
+ tftp->th_data, block + 1);
+ printf("\b+ ");
+#endif
+ send_ack(fd, tftp->th_data, port_number);
+ lost_packets++;
+ tftp_err->bad_tftp_packets++;
+ return 0;
+ } else if (tftp->th_data < block) {
+#ifdef __DEBUG__
+ printf
+ ("\nTFTP: Received block %x, expected block was %x\n",
+ tftp->th_data, block + 1);
+ printf("\b* ");
+#endif
+ /* This means that an old data packet appears (again);
+ * this happens sometimes if we don't answer fast enough
+ * and a timeout is generated on the server side;
+ * as we already have this packet we just ignore it */
+ tftp_err->bad_tftp_packets++;
+ return 0;
+ } else {
+ tftp_err->blocks_missed = block + 1;
+ tftp_err->blocks_received = tftp->th_data;
+ tftp_errno = -42;
+ goto error;
+ }
+ tftp_err->bad_tftp_packets = 0;
+ /* check if our buffer is large enough */
+ if (received_len + udph->uh_ulen - 12 > len) {
+ tftp_errno = -2;
+ goto error;
+ }
+ memcpy(buffer + received_len, &tftp->th_data + 1,
+ udph->uh_ulen - 12);
+ send_ack(fd, tftp->th_data, port_number);
+ received_len += udph->uh_ulen - 12;
+ /* Last packet reached if the payload of the UDP packet
+ * is smaller than blocksize + 12
+ * 12 = UDP header (8) + 4 bytes TFTP payload */
+ if (udph->uh_ulen < blocksize + 12) {
+ tftp_finished = 1;
+ return 0;
+ }
+ /* 0xffff is the highest block number possible
+ * see the TFTP RFCs */
+
+ if (block >= 0xffff && huge_load == 0) {
+ tftp_errno = -9;
+ goto error;
+ }
+ } else {
+#ifdef __DEBUG__
+ printf("Unknown packet %x\n", tftp->th_opcode);
+ printf("\b# ");
+#endif
+ tftp_err->bad_tftp_packets++;
+ return 0;
+ }
+
+ return 0;
+
+error:
+#ifdef __DEBUG__
+ printf("\nTFTP errno: %d\n", tftp_errno);
+#endif
+ tftp_finished = 1;
+ return tftp_errno;
+}
+
+/**
+ * TFTP: This function handles situation when "Destination unreachable"
+ * ICMP-error occurs during sending TFTP-packet.
+ *
+ * @param err_code Error Code (e.g. "Host unreachable")
+ */
+void
+handle_tftp_dun(uint8_t err_code)
+{
+ tftp_errno = - err_code - 10;
+ tftp_finished = 1;
+}
+
+/**
+ * TFTP: Interface function to load files via TFTP.
+ *
+ * @param _fn_ip contains the following configuration information:
+ * client IP, TFTP-server IP, filename to be loaded
+ * @param _buffer destination buffer for the file
+ * @param _len size of destination buffer
+ * @param _retries max number of retries
+ * @param _tftp_err contains info about TFTP-errors (e.g. lost packets)
+ * @param _mode NON ZERO - multicast, ZERO - unicast
+ * @param _blocksize blocksize for DATA-packets
+ * @return ZERO - error condition occurs
+ * NON ZERO - size of received file
+ */
+int
+tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len,
+ unsigned int _retries, tftp_err_t * _tftp_err,
+ int32_t _mode, int32_t _blocksize, int _ip_version)
+{
+ retries = _retries;
+ fn_ip = _fn_ip;
+ len = _len;
+ huge_load = _mode;
+ ip_version = _ip_version;
+ tftp_errno = 0;
+ tftp_err = _tftp_err;
+ tftp_err->bad_tftp_packets = 0;
+ tftp_err->no_packets = 0;
+
+ /* Default blocksize must be 512 for TFTP servers
+ * which do not support the RRQ blocksize option */
+ blocksize = 512;
+
+ /* Preferred blocksize - used as option for the read request */
+ if (_blocksize < 8)
+ _blocksize = 8;
+ else if (_blocksize > MAX_BLOCKSIZE)
+ _blocksize = MAX_BLOCKSIZE;
+ sprintf(blocksize_str, "%d", _blocksize);
+
+ printf(" Receiving data: ");
+ print_progress(-1, 0);
+
+ // Setting buffer to a non-zero address enabled handling of received TFTP packets.
+ buffer = _buffer;
+
+ set_timer(TICKS_SEC);
+ send_rrq(fn_ip->fd);
+
+ while (! tftp_finished) {
+ /* if timeout (no packet received) */
+ if(get_timer() <= 0) {
+ /* the server doesn't seem to retry let's help out a bit */
+ if (tftp_err->no_packets > 4 && port_number != -1
+ && block > 1) {
+ send_ack(fn_ip->fd, block, port_number);
+ }
+ else if (port_number == -1 && block == 0
+ && (tftp_err->no_packets&3) == 3) {
+ printf("\nRepeating TFTP read request...\n");
+ send_rrq(fn_ip->fd);
+ }
+ tftp_err->no_packets++;
+ set_timer(TICKS_SEC);
+ }
+
+ /* handle received packets */
+ receive_ether(fn_ip->fd);
+
+ /* bad_tftp_packets are counted whenever we receive a TFTP packet
+ * which was not expected; if this gets larger than 'retries'
+ * we just exit */
+ if (tftp_err->bad_tftp_packets > retries) {
+ tftp_errno = -40;
+ break;
+ }
+
+ /* no_packets counts the times we have returned from receive_ether()
+ * without any packet received; if this gets larger than 'retries'
+ * we also just exit */
+ if (tftp_err->no_packets > retries) {
+ tftp_errno = -41;
+ break;
+ }
+ }
+
+ // Setting buffer to NULL disables handling of received TFTP packets.
+ buffer = NULL;
+
+ if (tftp_errno)
+ return tftp_errno;
+
+ print_progress(-1, received_len);
+ printf("\n");
+ if (lost_packets)
+ printf("Lost ACK packets: %d\n", lost_packets);
+
+ return received_len;
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.h
new file mode 100644
index 000000000..1cf1266fb
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+
+#ifndef _TFTP_H_
+#define _TFTP_H_
+
+#include <stdint.h>
+#include <netlib/ipv6.h>
+
+struct tftphdr {
+ int16_t th_opcode;
+ uint16_t th_data;
+};
+
+typedef struct {
+ uint32_t own_ip;
+ ip6_addr_t own_ip6;
+ uint32_t server_ip;
+ ip6_addr_t server_ip6;
+ ip6_addr_t dns_ip6;
+ int8_t filename[256];
+ int fd;
+} __attribute__ ((packed)) filename_ip_t ;
+
+typedef struct {
+ uint32_t bad_tftp_packets;
+ uint32_t no_packets;
+ uint32_t blocks_missed;
+ uint32_t blocks_received;
+} tftp_err_t;
+
+int tftp(filename_ip_t *, unsigned char *, int, unsigned int,
+ tftp_err_t *, int32_t mode, int32_t blocksize, int ip_version);
+int tftp_netsave(filename_ip_t *, uint8_t * buffer, int len,
+ int use_ci, unsigned int retries, tftp_err_t * tftp_err);
+
+int32_t handle_tftp(int fd, uint8_t *, int32_t);
+void handle_tftp_dun(uint8_t err_code);
+int parse_tftp_args(char buffer[], char *server_ip, char filename[], int fd, int len);
+
+#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c
new file mode 100644
index 000000000..db29bc90f
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c
@@ -0,0 +1,151 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+
+#include <udp.h>
+#include <sys/socket.h>
+#include <dhcp.h>
+#include <dhcpv6.h>
+#include <dns.h>
+#ifdef USE_MTFTP
+#include <mtftp.h>
+#else
+#include <tftp.h>
+#endif
+
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+
+#ifdef USE_MTFTP
+
+uint16_t net_tftp_uport;
+uint16_t net_mtftp_uport;
+
+void net_set_tftp_port(uint16_t tftp_port) {
+ net_tftp_uport = tftp_port;
+}
+
+void net_set_mtftp_port(uint16_t tftp_port) {
+ net_mtftp_uport = tftp_port;
+}
+
+#endif
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+
+/**
+ * NET: Handles UDP-packets according to Receive-handle diagram.
+ *
+ * @param udp_packet UDP-packet to be handled
+ * @param packetsize Length of the packet
+ * @return ZERO - packet handled successfully;
+ * NON ZERO - packet was not handled (e.g. bad format)
+ * @see receive_ether
+ * @see udphdr
+ */
+int8_t
+handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize) {
+ struct udphdr * udph = (struct udphdr *) udp_packet;
+
+ if (packetsize < sizeof(struct udphdr))
+ return -1; // packet is too small
+
+ switch (htons(udph -> uh_dport)) {
+ case UDPPORT_BOOTPC:
+ if (udph -> uh_sport == htons(UDPPORT_BOOTPS))
+ return handle_dhcp(fd, udp_packet + sizeof(struct udphdr),
+ packetsize - sizeof(struct udphdr));
+ else
+ return -1;
+ case UDPPORT_DNSC:
+ if (udph -> uh_sport == htons(UDPPORT_DNSS))
+ return handle_dns(udp_packet + sizeof(struct udphdr),
+ packetsize - sizeof(struct udphdr));
+ else
+ return -1;
+ case UDPPORT_DHCPV6C:
+ return handle_dhcpv6(udp_packet+sizeof(struct udphdr),
+ packetsize - sizeof(struct udphdr));
+ case UDPPORT_TFTPC:
+#ifdef USE_MTFTP
+ return handle_tftp(fd, udp_packet + sizeof(struct udphdr),
+ packetsize - sizeof(struct udphdr));
+#else
+ return handle_tftp(fd, udp_packet, packetsize);
+#endif
+ default:
+#ifdef USE_MTFTP
+ if (htons(udph -> uh_dport) == net_tftp_uport)
+ return handle_tftp(fd, udp_packet + sizeof(struct udphdr),
+ packetsize - sizeof(struct udphdr));
+ else if (htons(udph -> uh_dport) == net_mtftp_uport)
+ return handle_tftp(fd, udp_packet + sizeof(struct udphdr),
+ packetsize - sizeof(struct udphdr));
+#endif
+ return -1;
+ }
+}
+
+/**
+ * NET: This function handles situation when "Destination unreachable"
+ * ICMP-error occurs during sending UDP-packet.
+ *
+ * @param err_code Error Code (e.g. "Host unreachable")
+ * @param packet original UDP-packet
+ * @param packetsize length of the packet
+ * @see handle_icmp
+ */
+void
+handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) {
+ struct udphdr * udph = (struct udphdr *) udp_packet;
+
+ if (packetsize < sizeof(struct udphdr))
+ return; // packet is too small
+
+ switch (htons(udph -> uh_sport)) {
+ case UDPPORT_TFTPC:
+ handle_tftp_dun(err_code);
+ break;
+ }
+}
+
+/**
+ * NET: Creates UDP-packet. Places UDP-header in a packet and fills it
+ * with corresponding information.
+ * <p>
+ * Use this function with similar functions for other network layers
+ * (fill_ethhdr, fill_iphdr, fill_dnshdr, fill_btphdr).
+ *
+ * @param packet Points to the place where UDP-header must be placed.
+ * @param packetsize Size of the packet in bytes incl. this hdr and data.
+ * @param src_port UDP source port
+ * @param dest_port UDP destination port
+ * @see udphdr
+ * @see fill_ethhdr
+ * @see fill_iphdr
+ * @see fill_dnshdr
+ * @see fill_btphdr
+ */
+void
+fill_udphdr(uint8_t * packet, uint16_t packetsize,
+ uint16_t src_port, uint16_t dest_port) {
+ struct udphdr * udph = (struct udphdr *) packet;
+
+ udph -> uh_sport = htons(src_port);
+ udph -> uh_dport = htons(dest_port);
+ udph -> uh_ulen = htons(packetsize);
+ udph -> uh_sum = htons(0);
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h
new file mode 100644
index 000000000..1ba9332ce
--- /dev/null
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+#ifndef _UDP_H
+#define _UDP_H
+
+#include <stdint.h>
+
+#define IPTYPE_UDP 17
+
+#define UDPPORT_BOOTPS 67 /**< UDP port of BootP/DHCP-server */
+#define UDPPORT_BOOTPC 68 /**< UDP port of BootP/DHCP-client */
+#define UDPPORT_DNSS 53 /**< UDP port of DNS-server */
+#define UDPPORT_DNSC 32769 /**< UDP port of DNS-client */
+#define UDPPORT_TFTPC 2001 /**< UDP port of TFTP-client */
+#define UDPPORT_DHCPV6C 546 /**< UDP port of DHCPv6-client */
+
+/** \struct udphdr
+ * A header for UDP-packets.
+ * For more information see RFC 768.
+ */
+struct udphdr {
+ uint16_t uh_sport; /**< Source port */
+ uint16_t uh_dport; /**< Destinantion port */
+ uint16_t uh_ulen; /**< Length in octets, incl. this header and data */
+ uint16_t uh_sum; /**< Checksum */
+};
+typedef struct udphdr udp_hdr_t;
+
+typedef int32_t *(*handle_upper_udp_t)(uint8_t *, int32_t);
+typedef void *(*handle_upper_udp_dun_t)(uint8_t);
+
+/* Handles UDP-packets that are detected by any network layer. */
+extern int8_t handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize);
+
+/* Handles UDP related ICMP-Dest.Unreachable packets that are detected by
+ * the network layers. */
+extern void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code);
+
+/* fills udp header */
+extern void fill_udphdr(uint8_t *packet, uint16_t packetsize,
+ uint16_t src_port, uint16_t dest_port);
+
+#ifdef USE_MTFTP
+extern void net_set_tftp_port(uint16_t tftp_port);
+extern void net_set_mtftp_port(uint16_t tftp_port);
+#endif
+
+#endif