summaryrefslogtreecommitdiffstats
path: root/rtems
diff options
context:
space:
mode:
authorVijay Kumar Banerjee <vijay@rtems.org>2021-02-03 19:46:50 -0700
committerVijay Kumar Banerjee <vijay@rtems.org>2021-02-24 19:01:17 -0700
commitfbc7459c2c3a86a4d94e19463417b759900ff51c (patch)
tree19d5451b8cee3d0c51a432c23bd598eafe9a53b0 /rtems
downloadrtems-net-legacy-fbc7459c2c3a86a4d94e19463417b759900ff51c.tar.bz2
Initial Commit: Add all files from RTEMS libnetworking directory
Diffstat (limited to 'rtems')
-rw-r--r--rtems/bootp.h44
-rw-r--r--rtems/bsdnet/_types.h41
-rw-r--r--rtems/bsdnet/servers.h18
-rw-r--r--rtems/dhcp.h47
-rw-r--r--rtems/mkrootfs.c248
-rw-r--r--rtems/mkrootfs.h80
-rw-r--r--rtems/rtems_bootp.c42
-rw-r--r--rtems/rtems_bsdnet.h339
-rw-r--r--rtems/rtems_bsdnet_internal.h285
-rw-r--r--rtems/rtems_bsdnet_malloc_starvation.c19
-rw-r--r--rtems/rtems_dhcp.c1287
-rw-r--r--rtems/rtems_dhcp_failsafe.c380
-rw-r--r--rtems/rtems_dhcp_failsafe.h64
-rw-r--r--rtems/rtems_glue.c1264
-rw-r--r--rtems/rtems_malloc_mbuf.c33
-rw-r--r--rtems/rtems_mii_ioctl.c172
-rw-r--r--rtems/rtems_mii_ioctl.h139
-rw-r--r--rtems/rtems_mii_ioctl_kern.c260
-rw-r--r--rtems/rtems_netdb.h52
-rw-r--r--rtems/rtems_netinet_in.h80
-rw-r--r--rtems/rtems_select.c179
-rw-r--r--rtems/rtems_showicmpstat.c70
-rw-r--r--rtems/rtems_showifstat.c157
-rw-r--r--rtems/rtems_showipstat.c68
-rw-r--r--rtems/rtems_showmbuf.c69
-rw-r--r--rtems/rtems_showroute.c240
-rw-r--r--rtems/rtems_showtcpstat.c106
-rw-r--r--rtems/rtems_showudpstat.c52
-rw-r--r--rtems/rtems_socketpair.c53
-rw-r--r--rtems/rtems_syscall.c835
-rw-r--r--rtems/rtems_syscall.h70
-rw-r--r--rtems/rtems_syscall_api.c22
-rw-r--r--rtems/sghostname.c54
33 files changed, 6869 insertions, 0 deletions
diff --git a/rtems/bootp.h b/rtems/bootp.h
new file mode 100644
index 0000000..4891430
--- /dev/null
+++ b/rtems/bootp.h
@@ -0,0 +1,44 @@
+/* Subroutines from cpukit/libnetworking/nfs/bootp_subr.c */
+
+#if !defined (__RTEMS_BOOTP_H__)
+#define __RTEMS_BOOTP_H__
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#if __cplusplus
+extern "C"
+{
+#endif
+
+struct bootp_packet;
+struct proc;
+struct ifreq;
+struct socket;
+struct sockaddr_in;
+
+bool bootpc_init(bool, bool);
+
+int bootpc_call(
+ struct bootp_packet *call,
+ struct bootp_packet *reply,
+ struct proc *procp,
+ const void *exp_vend,
+ size_t exp_vend_len);
+int bootpc_fakeup_interface(struct ifreq *ireq,
+ struct socket *so,
+ struct proc *procp);
+int bootpc_adjust_interface(struct ifreq *ireq,
+ struct socket *so,
+ struct sockaddr_in *myaddr,
+ struct sockaddr_in *netmask,
+ struct sockaddr_in *gw,
+ struct proc *procp);
+
+void *bootp_strdup_realloc(char *dst, const char *src);
+
+#if __cplusplus
+}
+#endif
+
+#endif
diff --git a/rtems/bsdnet/_types.h b/rtems/bsdnet/_types.h
new file mode 100644
index 0000000..d557e31
--- /dev/null
+++ b/rtems/bsdnet/_types.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/_types.h,v 1.21 2005/03/22 01:19:17 das Exp $
+ */
+
+
+#ifndef _RTEMS_BSDNET__TYPES_H_
+#define _RTEMS_BSDNET__TYPES_H_
+
+#include <stdint.h>
+
+/*
+ * Standard type definitions.
+ */
+typedef uint8_t __sa_family_t;
+typedef uint32_t __socklen_t;
+
+#endif /* !_RTEMS_BSDNET_TYPES_H_ */
diff --git a/rtems/bsdnet/servers.h b/rtems/bsdnet/servers.h
new file mode 100644
index 0000000..a9db74a
--- /dev/null
+++ b/rtems/bsdnet/servers.h
@@ -0,0 +1,18 @@
+/**
+ * @file
+ */
+
+
+#ifndef _RTEMS_BSDNET_SERVERS_H
+#define _RTEMS_BSDNET_SERVERS_H
+
+extern struct in_addr *rtems_bsdnet_ntpserver;
+extern int rtems_bsdnet_ntpserver_count;
+
+/*
+ * Network configuration
+ */
+extern struct in_addr *rtems_bsdnet_nameserver;
+extern int rtems_bsdnet_nameserver_count;
+
+#endif /* _RTEMS_BSDNET_SERVERS_H */
diff --git a/rtems/dhcp.h b/rtems/dhcp.h
new file mode 100644
index 0000000..eb7f42d
--- /dev/null
+++ b/rtems/dhcp.h
@@ -0,0 +1,47 @@
+/*
+ ------------------------------------------------------------------------
+
+ Copyright Cybertec Pty Ltd, 2005
+ All rights reserved Cybertec Pty Ltd, 2005
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+
+ ------------------------------------------------------------------------
+ */
+
+/**
+ @file
+
+ DHCP Server interface.
+*/
+
+#if !defined (__RTEMS_DHCP_H__)
+#define __RTEMS_DHCP_H__
+
+#if __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * Perform DHCP.
+ */
+void rtems_bsdnet_do_dhcp (void);
+int rtems_bsdnet_do_dhcp_timeout (void);
+void rtems_bsdnet_dhcp_down (void);
+
+/*
+ * Maintain a DHCP offer that has already been accepted.
+ */
+void rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid,
+ unsigned long lease_time,
+ unsigned long elapsed_time,
+ unsigned long ip_address,
+ unsigned long srv_address,
+ const char *hostname);
+
+#if __cplusplus
+}
+#endif
+
+#endif
diff --git a/rtems/mkrootfs.c b/rtems/mkrootfs.c
new file mode 100644
index 0000000..9414eae
--- /dev/null
+++ b/rtems/mkrootfs.c
@@ -0,0 +1,248 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ ------------------------------------------------------------------------
+
+ Copyright Cybertec Pty Ltd, 2000
+ All rights reserved Cybertec Pty Ltd, 2000
+
+ COPYRIGHT (c) 1989-1998.
+ On-Line Applications Research Corporation (OAR).
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution or at
+
+ http://www.rtems.org/license/LICENSE.
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+
+ ------------------------------------------------------------------------
+
+ Set of helpers when creating a root file system. The root filesystem
+ in RTEMS is the In Memory Filesystem (IMFS). We could copy an exiting
+ filesystem to here, how-ever a number of files can have target
+ specific initialisation info which we need to write.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <rtems/mkrootfs.h>
+#include <rtems/libio.h>
+#include <rtems/endian.h>
+
+/*
+ * A table a list of names and their modes.
+ */
+
+typedef struct rtems_rootfs_dir_table
+{
+ const char *name;
+ mode_t mode;
+} rtems_rootfs_dir_table;
+
+/*
+ * Table of directorys to make.
+ */
+
+static const rtems_rootfs_dir_table default_directories[] =
+{
+ { "/bin", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH },
+ { "/etc", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH },
+ { "/dev", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH },
+ { "/usr/bin", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH }
+};
+
+#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH)
+#define MKDIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+
+/*
+ * Create enough files to support the networking stack.
+ * Points to a table of strings.
+ */
+
+int
+rtems_rootfs_file_append (const char *file,
+ mode_t omode,
+ const int line_cnt,
+ const char **lines)
+{
+ struct stat sb;
+ int fd;
+ int i;
+
+ /*
+ * See is a file exists. If it does not, create the
+ * file and the path to the file.
+ */
+
+ fd = -1;
+
+ if (stat(file, &sb))
+ {
+ if (errno == ENOENT)
+ {
+ /*
+ * Get the path to the file if one exists and create the
+ * path. If it exists nothing happens.
+ */
+
+ size_t i = strlen (file);
+
+ while (i)
+ {
+ if (file[i] == '/')
+ {
+ char path[128];
+
+ if (i >= sizeof path)
+ {
+ printf ("root fs, path too long `%s'\n", file);
+ return -1;
+ }
+
+ strncpy (path, file, i);
+ path[i] = '\0';
+
+ if (rtems_mkdir (path, MKDIR_MODE))
+ return -1;
+ break;
+ }
+ i--;
+ }
+
+ if ((fd = open (file, O_CREAT | O_APPEND | O_WRONLY, omode)) < 0)
+ {
+ printf ("root fs, cannot create file `%s' : %s\n",
+ file, strerror (errno));
+ return -1;
+ }
+ }
+ }
+
+ if (fd < 0)
+ {
+ if ((fd = open (file, O_APPEND | O_WRONLY)) < 0)
+ {
+ printf ("root fs, cannot open file `%s' : %s\n",
+ file, strerror (errno));
+ return -1;
+ }
+ }
+
+ for (i = 0; i < line_cnt; i++)
+ {
+ size_t len = strlen (lines[i]);
+
+ if (len)
+ {
+ if (write (fd, lines[i], strlen (lines[i])) < 0)
+ {
+ close (fd);
+ printf ("root fs, cannot write to `%s' : %s\n",
+ file, strerror (errno));
+ return -1;
+ }
+ }
+ }
+
+ return close (fd);
+}
+
+/*
+ * Write hosts record.
+ */
+
+int
+rtems_rootfs_append_host_rec (in_addr_t cip,
+ const char *cname,
+ const char *dname)
+{
+ char buf[128];
+ char *bufp = buf;
+ const char *bufl[1];
+ struct in_addr ip;
+
+ ip.s_addr = cip;
+
+ if (cname && strlen (cname))
+ {
+ char addrbuf[INET_ADDRSTRLEN];
+
+ snprintf (bufp, sizeof (buf), "%s\t\t%s", inet_ntoa_r (ip, addrbuf), cname);
+ bufp += strlen (buf);
+
+ if (dname && strlen (dname))
+ {
+ snprintf (bufp, sizeof (buf), "\t\t%s.%s", cname, dname);
+ bufp += strlen (buf);
+ }
+
+ strcat (buf, "\n");
+
+ bufl[0] = buf;
+
+ if (rtems_rootfs_file_append ("/etc/hosts", MKFILE_MODE, 1, bufl) < 0)
+ return -1;
+ }
+ else
+ {
+ printf ("rootfs hosts rec append, no cname supplied\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Create a root file system.
+ */
+
+int
+rtems_create_root_fs (void)
+{
+ const char *lines[1];
+ size_t i;
+
+ /*
+ * Create the directories.
+ */
+
+ for (i = 0;
+ i < (sizeof (default_directories) / sizeof (rtems_rootfs_dir_table));
+ i++)
+ if (rtems_mkdir (default_directories[i].name,
+ default_directories[i].mode))
+ return -1;
+
+ /*
+ * The TCP/IP stack likes this one. If DNS does not work
+ * use the host file.
+ */
+
+ lines[0] = "hosts,bind\n";
+
+ if (rtems_rootfs_file_append ("/etc/host.conf", MKFILE_MODE, 1, lines))
+ return -1;
+
+ /*
+ * Create a `/etc/hosts' file.
+ */
+
+ if (rtems_rootfs_append_host_rec (htonl (0x7f000001), "localhost", "localdomain"))
+ return -1;
+
+ return 0;
+}
diff --git a/rtems/mkrootfs.h b/rtems/mkrootfs.h
new file mode 100644
index 0000000..1b1cb29
--- /dev/null
+++ b/rtems/mkrootfs.h
@@ -0,0 +1,80 @@
+/**
+ * @file
+ *
+ * RTEMS Root FS creation support.
+ */
+
+/*
+ Copyright Cybertec Pty Ltd, 2000
+ All rights reserved Cybertec Pty Ltd, 2000
+
+ COPYRIGHT (c) 1989-1998.
+ On-Line Applications Research Corporation (OAR).
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution or at
+ http://www.rtems.org/license/LICENSE.
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+*/
+
+#ifndef _RTEMS_MKROOTFS_H
+#define _RTEMS_MKROOTFS_H
+
+#include <sys/types.h> /* in_addr_t */
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Appends the lines to the a file. Create the file
+ * and builds the path if it does not exist.
+ *
+ * @param file
+ * @param omode
+ * @param line_cnt
+ * @param lines
+ *
+ * @return 0 on success, -1 on error
+ */
+
+int
+rtems_rootfs_file_append (const char *file,
+ mode_t omode,
+ const int line_cnt,
+ const char **lines);
+
+/**
+ * @brief Helper for bulding an /etc/hosts file.
+ *
+ * @param cip
+ * @param cname
+ * @param dname
+ *
+ * @return 0 on success, -1 on error
+ */
+
+int
+rtems_rootfs_append_host_rec (in_addr_t cip,
+ const char *cname,
+ const char *dname);
+
+/**
+ * Create a few common directories, plus a:
+ * /etc/passwd, /etc/group, /etc/host.conf, and
+ * /etc/hosts file.
+ *
+ * @return 0 on success, -1 on error
+ */
+
+int
+rtems_create_root_fs ( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/rtems/rtems_bootp.c b/rtems/rtems_bootp.c
new file mode 100644
index 0000000..134ae90
--- /dev/null
+++ b/rtems/rtems_bootp.c
@@ -0,0 +1,42 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <sys/types.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+
+#include "rtems/bootp.h"
+
+/*
+ * Perform a BOOTP request
+ */
+void
+rtems_bsdnet_do_bootp (void)
+{
+ bool ok;
+ rtems_bsdnet_semaphore_obtain ();
+ ok = bootpc_init (false, true);
+ rtems_bsdnet_semaphore_release ();
+ if (!ok)
+ panic ("rtems_bsdnet_do_bootp: bootp failed");
+}
+
+/*
+ * Perform a BOOTP request and update "standard" files in /etc
+ * with the results.
+ */
+void
+rtems_bsdnet_do_bootp_and_rootfs (void)
+{
+ bool ok;
+ rtems_bsdnet_semaphore_obtain ();
+ ok = bootpc_init (true, true);
+ rtems_bsdnet_semaphore_release ();
+ if (!ok)
+ panic ("rtems_bsdnet_do_bootp_and_rootfs: bootp failed");
+}
diff --git a/rtems/rtems_bsdnet.h b/rtems/rtems_bsdnet.h
new file mode 100644
index 0000000..4607f42
--- /dev/null
+++ b/rtems/rtems_bsdnet.h
@@ -0,0 +1,339 @@
+/**
+ * @file
+ */
+
+
+#ifndef _RTEMS_BSDNET_H
+#define _RTEMS_BSDNET_H
+
+#include <rtems.h>
+#include <sys/cpuset.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Values that may be obtained by BOOTP
+ */
+extern struct in_addr rtems_bsdnet_bootp_server_address;
+extern char *rtems_bsdnet_bootp_server_name;
+extern char *rtems_bsdnet_bootp_boot_file_name;
+extern char *rtems_bsdnet_bootp_cmdline;
+extern int32_t rtems_bsdnet_timeoffset;
+
+/*
+ * Manipulate routing tables
+ */
+struct sockaddr;
+struct rtentry;
+int rtems_bsdnet_rtrequest (
+ int req,
+ struct sockaddr *dst,
+ struct sockaddr *gateway,
+ struct sockaddr *netmask,
+ int flags,
+ struct rtentry **net_nrt);
+
+/*
+ * Diagnostics
+ */
+void rtems_bsdnet_show_inet_routes (void);
+void rtems_bsdnet_show_mbuf_stats (void);
+void rtems_bsdnet_show_if_stats (void);
+void rtems_bsdnet_show_ip_stats (void);
+void rtems_bsdnet_show_icmp_stats (void);
+void rtems_bsdnet_show_udp_stats (void);
+void rtems_bsdnet_show_tcp_stats (void);
+
+/*
+ * Network configuration
+ */
+struct rtems_bsdnet_ifconfig {
+ /*
+ * These three entries must be supplied for each interface.
+ */
+ char *name;
+
+ /*
+ * This function now handles attaching and detaching an interface.
+ * The parameter attaching indicates the operation being invoked.
+ * For older attach functions which do not have the extra parameter
+ * it will be ignored.
+ */
+ int (*attach)(struct rtems_bsdnet_ifconfig *conf, int attaching);
+
+ /*
+ * Link to next interface
+ */
+ struct rtems_bsdnet_ifconfig *next;
+
+ /*
+ * The following entries may be obtained
+ * from BOOTP or explicitily supplied.
+ */
+ char *ip_address;
+ char *ip_netmask;
+ void *hardware_address;
+
+ /*
+ * The driver assigns defaults values to the following
+ * entries if they are not explicitly supplied.
+ */
+ int ignore_broadcast;
+ int mtu;
+ int rbuf_count;
+ int xbuf_count;
+
+ /*
+ * For external ethernet controller board the following
+ * parameters are needed
+ */
+ unsigned int port; /* port of the board */
+ unsigned int irno; /* irq of the board */
+ unsigned int bpar; /* memory of the board */
+
+ /*
+ * Driver control block pointer. Typcially this points to the driver's
+ * controlling structure. You set this when you have the structure allocated
+ * externally to the driver.
+ */
+ void *drv_ctrl;
+
+};
+
+struct rtems_bsdnet_config {
+ /*
+ * This entry points to the head of the ifconfig chain.
+ */
+ struct rtems_bsdnet_ifconfig *ifconfig;
+
+ /*
+ * This entry should be rtems_bsdnet_do_bootp if BOOTP
+ * is being used to configure the network, and NULL
+ * if BOOTP is not being used.
+ */
+ void (*bootp)(void);
+
+ /*
+ * The remaining items can be initialized to 0, in
+ * which case the default value will be used.
+ */
+ rtems_task_priority network_task_priority; /* 100 */
+ unsigned long mbuf_bytecount; /* 64 kbytes */
+ unsigned long mbuf_cluster_bytecount; /* 128 kbytes */
+ char *hostname; /* BOOTP */
+ char *domainname; /* BOOTP */
+ char *gateway; /* BOOTP */
+ char *log_host; /* BOOTP */
+ char *name_server[3]; /* BOOTP */
+ char *ntp_server[3]; /* BOOTP */
+ /*
+ * Default "multiplier" on buffer size. This is
+ * claimed by the TCP/IP implementation to be for
+ * efficiency but you will have to measure the
+ * benefit for buffering beyond double buffering
+ * in your own application.
+ *
+ * The default value is 2.
+ *
+ * See kern/uipc_socket2.c for details.
+ */
+ unsigned long sb_efficiency;
+ /*
+ * Default UDP buffer sizes PER SOCKET!!
+ *
+ * TX = 9216 -- max datagram size
+ * RX = 40 * (1024 + sizeof(struct sockaddr_in))
+ *
+ * See netinet/udp_usrreq.c for details
+ */
+ unsigned long udp_tx_buf_size;
+ unsigned long udp_rx_buf_size;
+ /*
+ * Default UDP buffer sizes PER SOCKET!!
+ *
+ * TX = 16 * 1024
+ * RX = 16 * 1024
+ *
+ * See netinet/tcp_usrreq.c for details
+ */
+ unsigned long tcp_tx_buf_size;
+ unsigned long tcp_rx_buf_size;
+
+ /*
+ * Default Network Tasks CPU Affinity
+ */
+#ifdef RTEMS_SMP
+ const cpu_set_t *network_task_cpuset;
+ size_t network_task_cpuset_size;
+#endif
+};
+
+/*
+ * Default global device configuration structure. This is scanned
+ * by the initialize network function. Check the network demo's for
+ * an example of the structure. Like the RTEMS configuration tables,
+ * they are not part of RTEMS but part of your application or bsp
+ * code.
+ */
+extern struct rtems_bsdnet_config rtems_bsdnet_config;
+
+/*
+ * Initialise the BSD stack, attach and `up' interfaces
+ * in the `rtems_bsdnet_config'. RTEMS must already be initialised.
+ */
+int rtems_bsdnet_initialize_network (void);
+
+/*
+ * Dynamic interface control. Drivers must free any resources such as
+ * memory, interrupts, io regions claimed during the `attach' and/or
+ * `up' operations when asked to `detach'.
+ * You must configure the interface after attaching it.
+ */
+void rtems_bsdnet_attach (struct rtems_bsdnet_ifconfig *ifconfig);
+void rtems_bsdnet_detach (struct rtems_bsdnet_ifconfig *ifconfig);
+
+/*
+ * Interface configuration. The commands are listed in `sys/sockio.h'.
+ */
+int rtems_bsdnet_ifconfig (const char *ifname, uint32_t cmd, void *param);
+
+void rtems_bsdnet_do_bootp (void);
+void rtems_bsdnet_do_bootp_and_rootfs (void);
+
+/* NTP tuning parameters */
+extern int rtems_bsdnet_ntp_retry_count;
+extern int rtems_bsdnet_ntp_timeout_secs;
+extern int rtems_bsdnet_ntp_bcast_timeout_secs;
+
+
+struct timestamp {
+ uint32_t integer;
+ uint32_t fraction;
+};
+
+/* Data is passed in network byte order */
+struct ntpPacketSmall {
+ uint8_t li_vn_mode;
+ uint8_t stratum;
+ int8_t poll_interval;
+ int8_t precision;
+ int32_t root_delay;
+ int32_t root_dispersion;
+ char reference_identifier[4];
+ struct timestamp reference_timestamp;
+ struct timestamp originate_timestamp;
+ struct timestamp receive_timestamp;
+ struct timestamp transmit_timestamp;
+};
+
+/* NOTE: packet data is *only* accessible from the callback
+ *
+ * 'callback' is invoked twice, once prior to sending a request
+ * to the server and one more time after receiving a valid reply.
+ * This allows for the user to measure round-trip times.
+ *
+ * Semantics of the 'state' parameter:
+ *
+ * state == 1: 1st call, just prior to sending request. The
+ * packet has been set up already but may be
+ * modified by the callback (e.g. to set the originate
+ * timestamp).
+ * state == -1: 1st call - no request will be sent but we'll
+ * wait for a reply from a broadcast server. The
+ * packet has not been set up.
+ * state == 0: 2nd call. The user is responsible for keeping track
+ * of the 'state' during the first call in order to
+ * know if it makes sense to calculate 'round-trip' times.
+ *
+ * RETURN VALUE: the callback should return 0 if processing the packet was
+ * successful and -1 on error in which case rtems_bsdnet_get_ntp()
+ * may try another server.
+ */
+typedef int (*rtems_bsdnet_ntp_callback_t)(
+ struct ntpPacketSmall *packet,
+ int state,
+ void *usr_data);
+
+/* Obtain time from a NTP server and call user callback to process data;
+ * socket parameter may be -1 to request the routine to open and close its own socket.
+ * Networking parameters as configured are used...
+ *
+ * It is legal to pass a NULL callback pointer. In this case, a default callback
+ * is used which determines the current time by contacting an NTP server. The current
+ * time is converted to a 'struct timespec' (seconds/nanoseconds) and passed into *usr_data.
+ * The caller is responsible for providing a memory area >= sizeof(struct timespec).
+ *
+ * RETURNS: 0 on success, -1 on failure.
+ */
+int rtems_bsdnet_get_ntp(int socket, rtems_bsdnet_ntp_callback_t callback, void *usr_data);
+
+int rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority);
+
+/*
+ * Callback to report BSD malloc starvation.
+ * The default implementation just prints a message but an application
+ * can provide its own version.
+ */
+void rtems_bsdnet_malloc_starvation(void);
+
+/*
+ * mbuf malloc interface to enable custom allocation of mbuf's
+ *
+ * May be declared in user code. If not, then the default is to
+ * malloc.
+ */
+void* rtems_bsdnet_malloc_mbuf(size_t size, int type);
+
+/*
+ * Possible values of the type parameter to rtems_bsdnet_malloc_mbuf to assist
+ * in allocation of the structure.
+ */
+#define MBUF_MALLOC_NMBCLUSTERS (0)
+#define MBUF_MALLOC_MCLREFCNT (1)
+#define MBUF_MALLOC_MBUF (2)
+
+/*
+ * RTEMS-specific socket wake-up additions previously part of <sys/socket.h>.
+ *
+ * An alternative in the LibBSD network stack for this is KQUEUE(2).
+ */
+
+#define SO_SNDWAKEUP 0x1020 /* wakeup when ready to send */
+#define SO_RCVWAKEUP 0x1021 /* wakeup when ready to receive */
+
+/*
+ * RTEMS additions for setting/getting `tap' function on incoming packets.
+ */
+struct ifnet;
+struct ether_header;
+struct mbuf;
+struct rtems_tap_ifreq {
+ char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ int (*ifr_tap)(struct ifnet *, struct ether_header *, struct mbuf *);
+};
+#define SIOCSIFTAP _IOW('i', 88, struct rtems_tap_ifreq) /* set tap function */
+#define SIOCGIFTAP _IOW('i', 89, struct rtems_tap_ifreq) /* get tap function */
+
+#define OSIOCGIFADDR _IOWR('i', 13, struct ifreq) /* get ifnet address */
+#define OSIOCGIFDSTADDR _IOWR('i', 15, struct ifreq) /* get p-p address */
+#define OSIOCGIFBRDADDR _IOWR('i', 18, struct ifreq) /* get broadcast addr */
+#define OSIOCGIFCONF _IOWR('i', 20, struct ifconf) /* get ifnet list */
+#define OSIOCGIFNETMASK _IOWR('i', 21, struct ifreq) /* get net addr mask */
+
+struct socket;
+
+struct sockwakeup {
+ void (*sw_pfn)(struct socket *, void *);
+ void *sw_arg;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTEMS_BSDNET_H */
diff --git a/rtems/rtems_bsdnet_internal.h b/rtems/rtems_bsdnet_internal.h
new file mode 100644
index 0000000..d103c56
--- /dev/null
+++ b/rtems/rtems_bsdnet_internal.h
@@ -0,0 +1,285 @@
+/*
+ * Declarations to fit FreeBSD to RTEMS.
+ *
+ *******************************************************************
+ * WARNING *
+ * This file should *never* be included by any application program *
+ *******************************************************************
+ */
+
+#ifndef _RTEMS_RTEMS_BSDNET_INTERNAL_H
+#define _RTEMS_RTEMS_BSDNET_INTERNAL_H
+
+#include <sys/_types.h>
+#include <rtems.h>
+#include <rtems/fs.h>
+#include <rtems/score/timecounter.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef __uintptr_t vm_offset_t;
+typedef __intptr_t vm_ooffset_t;
+typedef __uintptr_t vm_pindex_t;
+typedef __uintptr_t vm_size_t;
+
+#define _BSD_OFF_T_ int32_t
+#define _BSD_PID_T_ rtems_id
+#define _BSD_VA_LIST_ char *
+
+/* make sure we get the network versions of these */
+#include <machine/types.h>
+#include <machine/param.h>
+#include <machine/endian.h>
+#include <sys/cdefs.h>
+
+#include <sys/time.h>
+#include <sys/ioccom.h>
+
+struct mdproc {
+ int md_flags;
+ int *md_regs;
+};
+
+/*
+ * Other RTEMS/BSD glue
+ */
+struct socket;
+extern int soconnsleep (struct socket *so);
+extern void soconnwakeup (struct socket *so);
+#define splnet() 0
+#define splimp() 0
+#define splx(_s) do { (_s) = 0; (void) (_s); } while(0)
+
+/* to avoid warnings */
+void *memcpy(void *dest, const void *src, size_t n);
+void *memset(void *s, int c, size_t n);
+
+#define ovbcopy(f,t,n) bcopy(f,t,n)
+#define copyout(f,t,n) (memcpy(t,f,n),0)
+#define copyin(f,t,n) (memcpy(t,f,n),0)
+
+#define random() rtems_bsdnet_random()
+#define panic rtems_panic
+#define suser(a,b) 0
+
+#define microtime(_tvp) _Timecounter_Microtime(_tvp)
+
+#define hz rtems_bsdnet_ticks_per_second
+#define tick rtems_bsdnet_microseconds_per_tick
+
+#define log rtems_bsdnet_log
+
+/*
+ * Since we can't have two sys/types.h files, we'll hack around
+ * and copy the contents of the BSD sys/types.h to here....
+ */
+
+typedef u_int64_t u_quad_t; /* quads */
+typedef int64_t quad_t;
+typedef quad_t * qaddr_t;
+
+typedef void __sighandler_t(int);
+typedef __sighandler_t *sig_t; /* type of pointer to a signal function */
+#define NSIG 32
+
+#ifdef _KERNEL
+typedef int boolean_t;
+#endif
+
+#ifndef _POSIX_SOURCE
+/*
+ * minor() gives a cookie instead of an index since we don't want to
+ * change the meanings of bits 0-15 or waste time and space shifting
+ * bits 16-31 for devices that don't use them.
+ */
+#define major(x) ((int)(((u_int)(x) >> 8)&0xff)) /* major number */
+#define minor(x) ((int)((x)&0xffff00ff)) /* minor number */
+#define makedev(x,y) ((dev_t)(((x) << 8) | (y))) /* create dev_t */
+#endif
+
+#ifndef _BYTEORDER_PROTOTYPED
+#define _BYTEORDER_PROTOTYPED
+__BEGIN_DECLS
+__uint32_t htonl(__uint32_t);
+__uint16_t htons(__uint16_t);
+__uint32_t ntohl(__uint32_t);
+__uint16_t ntohs(__uint16_t);
+__END_DECLS
+#endif
+
+#ifndef _BYTEORDER_FUNC_DEFINED
+#define _BYTEORDER_FUNC_DEFINED
+#define htonl(x) __htonl(x)
+#define htons(x) __htons(x)
+#define ntohl(x) __ntohl(x)
+#define ntohs(x) __ntohs(x)
+#endif /* !_BYTEORDER_FUNC_DEFINED */
+
+#define NTOHS(x) (x) = ntohs(x)
+#define HTONS(x) (x) = htons(x)
+#define NTOHL(x) (x) = ntohl(x)
+#define HTONL(x) (x) = htonl(x)
+
+in_addr_t inet_addr(const char *);
+
+typedef quad_t rlim_t; /* resource limit */
+typedef u_int32_t fixpt_t; /* fixed point number */
+
+/*
+ * Forward structure declarations for function prototypes. We include the
+ * common structures that cross subsystem boundaries here; others are mostly
+ * used in the same place that the structure is defined.
+ */
+struct proc;
+struct pgrp;
+struct ucred;
+struct rusage;
+struct buf;
+struct tty;
+struct uio;
+struct rtems_bsdnet_ifconfig;
+
+/*
+ * Redo kernel memory allocation
+ */
+#define malloc(size,type,flags) rtems_bsdnet_malloc(size,type,flags)
+#define free(ptr,type) rtems_bsdnet_free(ptr,type)
+#define timeout(ftn,arg,ticks) rtems_bsdnet_timeout(ftn,arg,ticks)
+
+#define M_NOWAIT 0x0001
+void *rtems_bsdnet_malloc (size_t size, int type, int flags);
+void rtems_bsdnet_free (void *addr, int type);
+
+void rtems_bsdnet_semaphore_obtain (void);
+void rtems_bsdnet_semaphore_release (void);
+void rtems_bsdnet_semaphore_obtain_recursive (uint32_t nest_count);
+uint32_t rtems_bsdnet_semaphore_release_recursive (void);
+void rtems_bsdnet_schednetisr (int n);
+int rtems_bsdnet_parse_driver_name (const struct rtems_bsdnet_ifconfig *config, char **namep);
+
+static inline unsigned long rtems_bsdnet_seconds_since_boot(void)
+{
+ return (unsigned long) rtems_clock_get_uptime_seconds() + 1UL;
+}
+
+unsigned long rtems_bsdnet_random (void);
+
+rtems_id rtems_bsdnet_newproc (
+ char *name,
+ int stacksize,
+ void (*entry)(void *),
+ void *arg
+);
+
+#ifdef RTEMS_SMP
+/* As rtems_bsdnet_newproc() but with ability to set CPU affinity too */
+rtems_id rtems_bsdnet_newproc_affinity (
+ char *name,
+ int stacksize,
+ void (*entry)(void *),
+ void *arg,
+ const cpu_set_t *set,
+ const size_t setsize
+);
+#endif
+
+rtems_status_code rtems_bsdnet_event_receive (
+ rtems_event_set event_in,
+ rtems_option option_set,
+ rtems_interval ticks,
+ rtems_event_set *event_out
+);
+
+static inline rtems_status_code rtems_bsdnet_event_send (
+ rtems_id task_id,
+ rtems_event_set event_in
+)
+{
+ return rtems_event_system_send (task_id, event_in);
+}
+
+/*
+ * Network configuration
+ */
+extern int rtems_bsdnet_ticks_per_second;
+extern int rtems_bsdnet_microseconds_per_tick;
+extern struct in_addr rtems_bsdnet_log_host_address;
+extern char *rtems_bsdnet_domain_name;
+
+/*
+ * Internal IOCTL command
+ */
+#define SIO_RTEMS_SHOW_STATS _IO('i', 250)
+
+/*
+ * Some extra prototypes
+ */
+int sethostname (const char *name, size_t namelen);
+void domaininit (void *);
+void ifinit (void *);
+void ipintr (void);
+void arpintr (void);
+int socket (int, int, int);
+int ioctl (int, ioctl_command_t, ...);
+
+/*
+ * Events used by networking routines.
+ * Everything will break if the application
+ * tries to use these events or if the `sleep'
+ * events are equal to any of the NETISR * events.
+ */
+#define SBWAIT_EVENT RTEMS_EVENT_SYSTEM_NETWORK_SBWAIT
+#define SOSLEEP_EVENT RTEMS_EVENT_SYSTEM_NETWORK_SOSLEEP
+#define NETISR_IP_EVENT (1L << NETISR_IP)
+#define NETISR_ARP_EVENT (1L << NETISR_ARP)
+#define NETISR_EVENTS (NETISR_IP_EVENT|NETISR_ARP_EVENT)
+#if (SBWAIT_EVENT & SOSLEEP_EVENT & NETISR_EVENTS & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE)
+# error "Network event conflict"
+#endif
+
+struct socket *rtems_bsdnet_fdToSocket(int fd);
+
+void sysctl_register_all(void *);
+
+void rtems_set_udp_buffer_sizes(u_long, u_long);
+
+void rtems_set_tcp_buffer_sizes(u_long, u_long);
+
+void rtems_set_sb_efficiency(u_long);
+
+#define IFF_OACTIVE IFF_DRV_OACTIVE
+#define IFF_RUNNING IFF_DRV_RUNNING
+
+struct ifaddr;
+void ifafree(struct ifaddr *);
+
+struct ifnet;
+struct mbuf;
+struct sockaddr;
+struct rtentry;
+int looutput(struct ifnet *,
+ struct mbuf *, struct sockaddr *, struct rtentry *);
+
+typedef u_long tcp_cc; /* connection count per rfc1644 */
+
+#define TCPOPT_TSTAMP_HDR \
+ (uint32_t)(((uint32_t)TCPOPT_NOP<<24)| \
+ ((uint32_t)TCPOPT_NOP<<16)| \
+ ((uint32_t)TCPOPT_TIMESTAMP<<8)| \
+ ((uint32_t)TCPOLEN_TIMESTAMP))
+
+#define TCPOPT_CC 11 /* CC options: RFC-1644 */
+#define TCPOPT_CCNEW 12
+#define TCPOPT_CCECHO 13
+#define TCPOLEN_CC 6
+#define TCPOLEN_CC_APPA (TCPOLEN_CC+2)
+#define TCPOPT_CC_HDR(ccopt) \
+ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|(ccopt)<<8|TCPOLEN_CC)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTEMS_RTEMS_BSDNET_INTERNAL_H */
diff --git a/rtems/rtems_bsdnet_malloc_starvation.c b/rtems/rtems_bsdnet_malloc_starvation.c
new file mode 100644
index 0000000..c5ccd8c
--- /dev/null
+++ b/rtems/rtems_bsdnet_malloc_starvation.c
@@ -0,0 +1,19 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * Routine called when malloc() is not succeeding. This can be overridden
+ * by a BSP.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <rtems/rtems_bsdnet.h>
+
+void
+rtems_bsdnet_malloc_starvation(void)
+{
+ printf ("rtems_bsdnet_malloc still waiting.\n");
+}
diff --git a/rtems/rtems_dhcp.c b/rtems/rtems_dhcp.c
new file mode 100644
index 0000000..6a153a4
--- /dev/null
+++ b/rtems/rtems_dhcp.c
@@ -0,0 +1,1287 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * DCHP client for RTEMS
+ * Andrew Bythell, <abythell@nortelnetworks.com>
+ * based on and uses subroutines from c/src/libnetworking/nfs/bootp_subr.c
+ */
+
+/*
+ * DHCP task added.
+ * Brendan Gannon, <bgannon@cybertec.com.au>
+ */
+
+/*
+ * Added interface to terminate DHCP task, and removed panics.
+ * Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind
+ * Maarten Van Es <maarten@mind.be>, Essensium/Mind
+ */
+
+/*
+ * Copyright (c) 1995 Gordon Ross, Adam Glass
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/bsdnet/servers.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/sockio.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN */
+#include <sys/systm.h>
+#include <sys/socketvar.h> /* for socreat() soclose() */
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <netinet/in.h> /* for NBO-HBO conversions */
+#include <net/if_types.h> /* for IFT_ETHER */
+#include <net/if_dl.h> /* for LLADDR */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <rtems/mkrootfs.h>
+
+#include "rtems/dhcp.h"
+#include "rtems/bootp.h"
+
+#ifndef EALEN
+#define EALEN 6
+#endif
+
+/*
+ *DHCP flags
+ */
+#define DHCP_BROADCAST 0x8000
+#define DHCP_UNICAST 0x0000
+
+/*
+ * DHCP Op Codes
+ */
+#define DHCP_BOOTREQUEST 1
+#define DHCP_BOOTREPLY 2
+
+/*
+ * DHCP Messages
+ */
+#define DHCP_DISCOVER 1
+#define DHCP_OFFER 2
+#define DHCP_REQUEST 3
+#define DHCP_DECLINE 4
+#define DHCP_ACK 5
+#define DHCP_NACK 6
+#define DHCP_RELEASE 7
+
+/*
+ * DHCP Options
+ */
+#define DHCP_OPTION_PAD 0
+#define DHCP_SUBNET 1
+#define DHCP_GATEWAY 3
+#define DHCP_DNS 6
+#define DHCP_HOST 12
+#define DHCP_DOMAIN_NAME 15
+#define DHCP_NETMASK 28
+#define DHCP_REQUESTED_IP 50
+#define DHCP_LEASE 51
+#define DHCP_MESSAGE 53
+#define DHCP_SERVER 54
+#define DHCP_PARAMETERS 55
+#define DHCP_OPTION_END 255
+
+/*
+ * Definitions from RFC
+ */
+struct dhcp_packet
+{
+ u_int8_t op;
+ u_int8_t htype;
+ u_int8_t hlen;
+ u_int8_t hops;
+ u_int32_t xid;
+ u_int16_t secs;
+ u_int16_t flags;
+ struct in_addr ciaddr;
+ struct in_addr yiaddr;
+ struct in_addr siaddr;
+ struct in_addr giaddr;
+ unsigned char chaddr[16];
+ char sname[64];
+ char file[128];
+ unsigned char vend[312];
+};
+
+/*
+ * Variables
+ */
+static int dhcp_option_overload = 0;
+static char dhcp_gotgw = 0;
+static char dhcp_gotnetmask = 0;
+static char dhcp_gotserver = 0;
+static char dhcp_gotlogserver = 0;
+static struct sockaddr_in dhcp_netmask;
+static struct sockaddr_in dhcp_gw;
+static char *dhcp_hostname;
+static int dhcp_message_type = 0;
+static unsigned long dhcp_lease_time;
+static unsigned long dhcp_elapsed_time = 0;
+static const char dhcp_magic_cookie[4] = { 99, 130, 83, 99 };
+static const char dhcp_request_parameters[5] = { DHCP_SUBNET,
+ DHCP_GATEWAY,
+ DHCP_DNS,
+ DHCP_HOST,
+ DHCP_DOMAIN_NAME };
+#define NUM_NAMESERVERS \
+ (sizeof rtems_bsdnet_config.name_server / sizeof rtems_bsdnet_config.name_server[0])
+static struct in_addr rtems_dhcpd_nameserver[NUM_NAMESERVERS];
+static int rtems_dhcpd_nameserver_count = 0;
+
+/*
+ * Clean any DNS entries add by a DHCP request.
+ */
+static void
+clean_dns_entries (void)
+{
+ int e;
+ for (e = 0; e < rtems_dhcpd_nameserver_count; ++e)
+ {
+ int n;
+ for (n = 0; n < rtems_bsdnet_nameserver_count; ++ n)
+ {
+ if (memcmp (&rtems_dhcpd_nameserver[e], &rtems_bsdnet_nameserver[n], 4) == 0)
+ {
+ if (n < (NUM_NAMESERVERS - 1))
+ memmove (&rtems_bsdnet_nameserver[n],
+ &rtems_bsdnet_nameserver[n + 1],
+ (NUM_NAMESERVERS - n - 1) * 4);
+ --rtems_bsdnet_nameserver_count;
+ }
+ }
+ }
+ rtems_dhcpd_nameserver_count = 0;
+}
+
+/*
+ * Format an IP address in dotted decimal.
+ */
+static void
+format_ip (unsigned long ip, char* buffer)
+{
+ sprintf (buffer,
+ "%lu.%lu.%lu.%lu",
+ (ip >> 24),
+ (ip >> 16) & 0xff,
+ (ip >> 8) & 0xff,
+ (ip & 0xff));
+
+ return;
+}
+
+/*
+ * Print the IP setup
+ */
+static void
+printsetup (const char *iface,
+ struct in_addr ip_addr,
+ struct in_addr mask_addr,
+ struct in_addr srv_addr,
+ struct in_addr gw_addr)
+{
+ unsigned long ip;
+ char ip_str[15];
+
+ printf ("dhcpc: %s: ", iface);
+
+ ip = ntohl (ip_addr.s_addr);
+ format_ip (ip, ip_str);
+ printf ("inet: %-15s ", ip_str);
+
+ ip = ntohl (mask_addr.s_addr);
+ format_ip (ip, ip_str);
+ printf ("mask: %-15s\n", ip_str);
+
+ ip = ntohl (srv_addr.s_addr);
+ format_ip (ip, ip_str);
+ printf (" srv: %-15s ", ip_str);
+
+ ip = ntohl (gw_addr.s_addr);
+ format_ip (ip, ip_str);
+ printf (" gw: %-15s\n", ip_str);
+
+ return;
+}
+
+/*
+ * Process options from the DHCP packet.
+ * Based on BOOTP routine.
+ */
+static void
+process_options (unsigned char *optbuf, int optbufSize)
+{
+ int j = 0;
+ int len;
+ int code, ncode;
+ char *p;
+
+ dhcp_message_type = 0;
+
+ ncode = optbuf[0];
+ while (j < optbufSize)
+ {
+ code = optbuf[j] = ncode;
+ if (code == 255)
+ return;
+ if (code == 0)
+ {
+ j++;
+ continue;
+ }
+ len = optbuf[j + 1];
+ j += 2;
+
+ if ((len + j) >= optbufSize)
+ {
+ printf ("Truncated field for code %d", code);
+ return;
+ }
+
+ ncode = optbuf[j + len];
+ optbuf[j + len] = '\0';
+ p = (char*) &optbuf[j];
+ j += len;
+
+ /*
+ * Process the option
+ */
+ switch (code)
+ {
+ case 1:
+ /* Subnet mask */
+ if (len != 4) {
+ printf ("dhcpc: subnet mask len is %d\n", len);
+ continue;
+ }
+ memcpy (&dhcp_netmask.sin_addr, p, 4);
+ dhcp_gotnetmask = 1;
+ break;
+
+ case 2:
+ /* Time offset */
+ if (len != 4) {
+ printf ("dhcpc: time offset len is %d\n", len);
+ continue;
+ }
+ memcpy (&rtems_bsdnet_timeoffset, p, 4);
+ rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset);
+ break;
+
+ case 3:
+ /* Routers */
+ if (len % 4) {
+ printf ("dhcpc: Router Len is %d\n", len);
+ continue;
+ }
+ if (len > 0)
+ {
+ memcpy (&dhcp_gw.sin_addr, p, 4);
+ dhcp_gotgw = 1;
+ }
+ break;
+
+ case 42:
+ /* NTP servers */
+ if (len % 4) {
+ printf ("dhcpc: time server Len is %d\n", len);
+ continue;
+ }
+ {
+ int tlen = 0;
+ while ((tlen < len) &&
+ (rtems_bsdnet_ntpserver_count <
+ sizeof rtems_bsdnet_config.ntp_server /
+ sizeof rtems_bsdnet_config.ntp_server[0]))
+ {
+ memcpy (&rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count],
+ p + tlen, 4);
+ rtems_bsdnet_ntpserver_count++;
+ tlen += 4;
+ }
+ }
+ break;
+
+ case 6:
+ /* Domain Name servers */
+ if (len % 4) {
+ printf ("dhcpc: DNS Len is %d\n", len);
+ continue;
+ }
+ {
+ int dlen = 0;
+ while ((dlen < len) &&
+ (rtems_dhcpd_nameserver_count < NUM_NAMESERVERS) &&
+ (rtems_bsdnet_nameserver_count < NUM_NAMESERVERS))
+ {
+ memcpy (&rtems_dhcpd_nameserver
+ [rtems_dhcpd_nameserver_count], p + dlen, 4);
+ rtems_dhcpd_nameserver_count++;
+ memcpy (&rtems_bsdnet_nameserver
+ [rtems_bsdnet_nameserver_count], p + dlen, 4);
+ rtems_bsdnet_nameserver_count++;
+ dlen += 4;
+ }
+ }
+ break;
+
+ case 12:
+ /* Host name */
+ if (len >= MAXHOSTNAMELEN) {
+ printf ("dhcpc: hostname >= %d bytes\n", MAXHOSTNAMELEN);
+ len = MAXHOSTNAMELEN-1;
+ }
+ if (sethostname (p, len) < 0) {
+ printf ("dhcpc: can't set host name");
+ }
+ if (dhcp_hostname != NULL)
+ {
+ char *tmp = realloc (dhcp_hostname, len);
+ if (tmp != NULL) {
+ dhcp_hostname = tmp;
+ strncpy (dhcp_hostname, p, len);
+ } else { /* realloc failed */
+ printf ("dhcpc: realloc failed (%s:%d)", __FILE__, __LINE__);
+ free (dhcp_hostname, 0);
+ dhcp_hostname = NULL;
+ }
+ } else { /* dhcp_hostname == NULL */
+ dhcp_hostname = strndup (p, len);
+ }
+ break;
+
+ case 7:
+ /* Log servers */
+ if (len % 4) {
+ printf ("dhcpc: Log server Len is %d\n", len);
+ continue;
+ }
+ if (len > 0)
+ {
+ memcpy (&rtems_bsdnet_log_host_address, p, 4);
+ dhcp_gotlogserver = 1;
+ }
+ break;
+
+ case 15:
+ /* Domain name */
+ if (p[0])
+ {
+ rtems_bsdnet_domain_name = strdup (p);
+ }
+ break;
+
+ case 16: /* Swap server IP address. unused */
+ break;
+
+ case 50:
+ /* DHCP Requested IP Address */
+ if (len != 4)
+ printf ("dhcpc: DHCP option requested IP len is %d", len);
+ /*
+ * although nothing happens here, this case keeps the client
+ * from complaining about unknown options. The Requested IP
+ * is necessary to return to the server for a DHCP REQUEST
+ */
+ break;
+
+ case 51:
+ /* DHCP Lease Length */
+ if (len != 4) {
+ printf ("dhcpc: DHCP option lease-length len is %d", len);
+ continue;
+ }
+ memcpy (&dhcp_lease_time, &p[0], 4);
+ dhcp_lease_time = ntohl (dhcp_lease_time);
+ break;
+
+ case 52:
+ /* DHCP option override */
+ if (len != 1) {
+ printf ("dhcpc: DHCP option overload len is %d", len);
+ continue;
+ }
+ dhcp_option_overload = p[0];
+ break;
+
+ case 53:
+ /* DHCP message */
+ if (len != 1) {
+ printf ("dhcpc: DHCP message len is %d", len);
+ continue;
+ }
+ dhcp_message_type = p[0];
+ break;
+
+ case 128: /* Site-specific option for DHCP servers that
+ * a) don't supply tag 54
+ * and
+ * b) don't supply the server address in siaddr
+ * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab:
+ * Bootsrv s Site,128,IP,1,1
+ * and use that symbol in the macro that defines the client:
+ * Bootsrv=<tftp-server-ip-address>
+ */
+ case 54:
+ /* DHCP server */
+ if (len != 4) {
+ printf ("dhcpc: DHCP server len is %d", len);
+ continue;
+ }
+ memcpy (&rtems_bsdnet_bootp_server_address, p, 4);
+ dhcp_gotserver = 1;
+ break;
+
+ case 66:
+ /* DHCP server name option */
+ if (p[0])
+ rtems_bsdnet_bootp_server_name = strdup (p);
+ break;
+
+ case 67:
+ /* DHCP bootfile option */
+ if (p[0])
+ rtems_bsdnet_bootp_boot_file_name = strdup (p);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Generate the packet for a DHCP DISCOVER.
+ */
+static int
+dhcp_discover_req (struct dhcp_packet* call,
+ struct sockaddr_dl *sdl,
+ unsigned long *xid)
+{
+ int len = 0;
+
+ memset (call, 0, sizeof (struct dhcp_packet));
+
+ /*
+ * Send a DHCP DISCOVER Message
+ */
+ call->op = DHCP_BOOTREQUEST;
+ call->htype = 1; /* 10mb ethernet */
+ call->hlen = sdl->sdl_alen; /* Hardware address length */
+ call->hops = 0;
+ (*xid)++;
+ call->xid = htonl (*xid);
+ call->flags = htons (DHCP_BROADCAST);
+
+ memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen);
+
+ /*
+ * Magic cookie.
+ */
+ memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie));
+ len += sizeof (dhcp_magic_cookie);
+
+ /*
+ * DHCP Message type.
+ */
+ call->vend[len++] = DHCP_MESSAGE;
+ call->vend[len++] = 1;
+ call->vend[len++] = DHCP_DISCOVER;
+
+ /*
+ * If a host name is set add it to the request.
+ */
+ if (rtems_bsdnet_config.hostname && \
+ (strlen (rtems_bsdnet_config.hostname) > 1) &&
+ (strlen (rtems_bsdnet_config.hostname) < 32)) {
+ call->vend[len++] = DHCP_HOST;
+ call->vend[len++] = strlen (rtems_bsdnet_config.hostname);
+ memcpy (&call->vend[len],
+ rtems_bsdnet_config.hostname,
+ strlen (rtems_bsdnet_config.hostname));
+ len += strlen (rtems_bsdnet_config.hostname);
+ }
+
+ /*
+ * DHCP Parameter request list
+ */
+ call->vend[len++] = DHCP_PARAMETERS;
+ call->vend[len++] = sizeof (dhcp_request_parameters);
+ memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters));
+ len += sizeof (dhcp_request_parameters);
+
+ /*
+ * Lease time.
+ */
+ call->vend[len++] = DHCP_LEASE;
+ call->vend[len++] = 4;
+ memset (&call->vend[len], 0xFF, 4); /* request infinite lease time */
+ len += 4;
+
+ /*
+ * End.
+ */
+ call->vend[len++] = DHCP_OPTION_END;
+ call->secs = 0;
+
+ return len;
+}
+
+/*
+ * Generate the packet for a DHCP REQUEST.
+ */
+static int
+dhcp_request_req (struct dhcp_packet* call,
+ struct dhcp_packet* reply,
+ struct sockaddr_dl *sdl,
+ int broadcast)
+{
+ int len = 0;
+ unsigned long temp;
+ char *hostname;
+
+ memset (call, 0, sizeof (struct dhcp_packet));
+
+ /*
+ * Send a DHCP REQUEST Message
+ */
+ call->op = DHCP_BOOTREQUEST;
+ call->htype = 1; /* 10mb ethernet */
+ call->hlen = sdl->sdl_alen; /* Hardware address length */
+ call->hops = 0;
+ call->xid = reply->xid;
+ if (broadcast)
+ call->flags = htons (DHCP_BROADCAST);
+ else
+ {
+ call->flags = htons (DHCP_UNICAST);
+ call->ciaddr = reply->yiaddr;
+ }
+ memcpy (&call->chaddr, LLADDR (sdl), sdl->sdl_alen);
+
+ /*
+ * Magic cookie.
+ */
+ memcpy (&call->vend[len], dhcp_magic_cookie, sizeof (dhcp_magic_cookie));
+ len += sizeof (dhcp_magic_cookie);
+
+ /*
+ * DHCP Message type.
+ */
+ call->vend[len++] = DHCP_MESSAGE;
+ call->vend[len++] = 1;
+ call->vend[len++] = DHCP_REQUEST;
+
+ /*
+ * DHCP server
+ */
+ if (broadcast)
+ {
+ call->vend[len++] = DHCP_SERVER;
+ call->vend[len++] = sizeof (rtems_bsdnet_bootp_server_address);
+ memcpy (&call->vend[len], &rtems_bsdnet_bootp_server_address,
+ sizeof (rtems_bsdnet_bootp_server_address));
+ len += sizeof (rtems_bsdnet_bootp_server_address);
+ }
+
+ /*
+ * Requested IP
+ */
+ call->vend[len++] = DHCP_REQUESTED_IP;
+ call->vend[len++] = sizeof (reply->yiaddr);
+ memcpy (&call->vend[len], &reply->yiaddr, sizeof (reply->yiaddr));
+ len += sizeof (reply->yiaddr);
+
+ /*
+ * DHCP Parameter request list
+ */
+ call->vend[len++] = DHCP_PARAMETERS;
+ call->vend[len++] = sizeof (dhcp_request_parameters);
+ memcpy (&call->vend[len], &dhcp_request_parameters, sizeof (dhcp_request_parameters));
+ len += sizeof (dhcp_request_parameters);
+
+ /*
+ * Lease time.
+ * For the REQUEST, return the lease time the server offered.
+ */
+ call->vend[len++] = DHCP_LEASE;
+ call->vend[len++] = 4;
+ temp = htonl (dhcp_lease_time);
+ memcpy (&call->vend[len], &temp, sizeof (unsigned long));
+ len += 4;
+
+ /*
+ * Host name.
+ */
+ hostname = malloc (MAXHOSTNAMELEN, 0, M_NOWAIT);
+ if (hostname != NULL)
+ {
+ if (gethostname (hostname, MAXHOSTNAMELEN) == 0)
+ {
+ call->vend[len++] = DHCP_HOST;
+ call->vend[len++] = strlen (hostname);
+ strcpy ((char*) &call->vend[len], hostname);
+ len += strlen (hostname);
+ }
+ free (hostname, 0);
+ }
+
+ /*
+ * End.
+ */
+ call->vend[len++] = DHCP_OPTION_END;
+ call->secs = 0;
+
+ return len;
+}
+
+/*
+ * Variables for the DHCP task.
+ */
+static struct dhcp_packet dhcp_req;
+static rtems_id dhcp_task_id;
+
+/*
+ * The DHCP task counts until half the lease time has expired.
+ * When this period is up, it sends a DHCP REQUEST packet to the
+ * server again to renew the lease.
+ * If the lease is renewed, the task starts counting again.
+ * If the lease is not renewed, the task retries until it is.
+ *
+ * The task will not rebind if the lease is not renewed.
+ */
+static void
+dhcp_task (rtems_task_argument _sdl)
+{
+ unsigned long count;
+ struct dhcp_packet call;
+ struct sockaddr_dl *sdl;
+ rtems_event_set event_out;
+ unsigned int timeout = 0;
+ int error;
+ struct proc *procp = NULL;
+ rtems_status_code ev_st;
+
+ sdl = (struct sockaddr_dl *) _sdl;
+
+ count = dhcp_elapsed_time;
+
+ while (true)
+ {
+ /*
+ * Sleep until the next poll
+ */
+ timeout = RTEMS_MILLISECONDS_TO_TICKS (1000);
+ ev_st = rtems_event_receive (RTEMS_EVENT_0,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ timeout, &event_out);
+
+ /*
+ * Check if not a poll timeout. So when ANY event received, exit task.
+ * Actually, only event RTEMS_EVENT_0 sent from rtem_dhcp_failsafe.c
+ * if "failsafe" dhcp enabled when interface down. Otherwise, no
+ * event should occur, just timeout.
+ */
+ if(ev_st != RTEMS_TIMEOUT)
+ break;
+
+ count++;
+
+ if (count >= (dhcp_lease_time / 2))
+ {
+ rtems_bsdnet_semaphore_obtain ();
+
+ dhcp_request_req (&call, &dhcp_req, sdl, true);
+
+ /*
+ * Send the Request.
+ */
+ error = bootpc_call ((struct bootp_packet *)&call,
+ (struct bootp_packet *)&dhcp_req, procp, NULL, 0);
+ if (error) {
+ rtems_bsdnet_semaphore_release ();
+ printf ("DHCP call failed -- error %d", error);
+ continue;
+ }
+
+ /*
+ * Check for DHCP ACK/NACK
+ */
+ if (memcmp (&dhcp_req.vend[0],
+ dhcp_magic_cookie,
+ sizeof (dhcp_magic_cookie)) != 0)
+ {
+ rtems_bsdnet_semaphore_release ();
+ printf ("DHCP server did not send Magic Cookie.\n");
+ continue;
+ }
+
+ /*
+ * We have an ack. Clear the DNS entries that have been assigned by a previous
+ * DHCP request.
+ */
+ clean_dns_entries ();
+
+ /*
+ * Process this requests options.
+ */
+ process_options (&dhcp_req.vend[4], sizeof (dhcp_req.vend) - 4);
+
+ if (dhcp_message_type != DHCP_ACK)
+ {
+ rtems_bsdnet_semaphore_release ();
+ printf ("DHCP server did not accept the DHCP request");
+ continue;
+ }
+
+ rtems_bsdnet_semaphore_release ();
+
+ count = 0;
+ }
+ }
+
+
+ dhcp_task_id = 0;
+ printf ("dhcpc: exiting lease renewal task.\n");
+ rtems_task_exit();
+
+}
+
+/*
+ * Start the DHCP task.
+ */
+static rtems_status_code
+dhcp_start_task (struct sockaddr_dl *sdl,
+ struct dhcp_packet *reply,
+ int priority)
+{
+ rtems_status_code sc;
+
+ memcpy (&dhcp_req, reply, sizeof (struct dhcp_packet));
+
+ sc = rtems_task_create (rtems_build_name ('d','h','c','p'),
+ priority,
+ 2048,
+ RTEMS_PREEMPT |
+ RTEMS_NO_TIMESLICE |
+ RTEMS_NO_ASR |
+ RTEMS_INTERRUPT_LEVEL (0),
+ RTEMS_LOCAL,
+ &dhcp_task_id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+
+ sc = rtems_task_start (dhcp_task_id,
+ dhcp_task,
+ (rtems_task_argument) sdl);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Check if the chosen interface already has an IP.
+ */
+static int
+dhcp_interface_has_ip (struct ifreq *ireq, struct socket *so, struct proc *procp)
+{
+ struct sockaddr_in* sin;
+ int error;
+
+ /*
+ * Check if the interface is already up.
+ */
+ error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp);
+ if (error)
+ return 0;
+
+ if ((ireq->ifr_flags & IFF_UP) == 0)
+ return 0;
+
+ sin = (struct sockaddr_in *)&ireq->ifr_addr;
+ bzero ((caddr_t)sin, sizeof (struct sockaddr_in));
+ sin->sin_len = sizeof (struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ error = ifioctl (so, SIOCGIFADDR, (caddr_t)ireq, procp);
+ if (error)
+ return 0;
+
+ if (sin->sin_addr.s_addr != 0)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * DCHP Client Routine
+ * - The first DHCP offer is always accepted
+ * - No DHCP DECLINE message is sent if ARPing fails
+ *
+ * return value:
+ * 0: ok
+ * < 0: failed to startup or configure interface
+ */
+static int
+dhcp_init (int update_files)
+{
+ struct dhcp_packet call;
+ struct dhcp_packet reply;
+ static unsigned long xid = ~0xFF;
+ struct ifreq ireq;
+ struct ifnet *ifp;
+ struct socket *so;
+ int error;
+ struct sockaddr_in myaddr;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl = NULL;
+ struct proc *procp = NULL;
+ char expected_dhcp_payload[7];
+
+ clean_dns_entries();
+
+ /*
+ * If we are to update the files create the root
+ * file structure.
+ */
+ if (update_files)
+ if (rtems_create_root_fs () < 0) {
+ printf("Error creating the root filesystem.\nFile not created.\n");
+ update_files = 0;
+ }
+
+ /*
+ * Find a network interface.
+ */
+ for (ifp = ifnet; ifp != 0; ifp = ifp->if_next)
+ if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
+ break;
+ if (ifp == NULL){
+ printf ("dhcpc_init: no suitable interface\n");
+ return -1;
+ }
+
+ memset (&ireq, 0, sizeof (ireq));
+ sprintf (ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
+
+ if ((error = socreate (AF_INET, &so, SOCK_DGRAM, 0, procp)) != 0) {
+ printf ("dhcpc_init: socreate, error: %s\n", strerror(error));
+ return -1;
+ }
+
+ if (!dhcp_interface_has_ip (&ireq, so, procp))
+ bootpc_fakeup_interface (&ireq, so, procp);
+
+ /*
+ * Get HW address
+ */
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+ if (ifa->ifa_addr->sa_family == AF_LINK &&
+ (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
+ sdl->sdl_type == IFT_ETHER)
+ break;
+
+ if (!sdl){
+ printf ("dhcpc_init: Unable to find HW address\n");
+ soclose (so);
+ return -1;
+ }
+ if (sdl->sdl_alen != EALEN) {
+ printf ("dhcpc_init: HW address len is %d, expected value is %d\n",
+ sdl->sdl_alen, EALEN);
+ soclose (so);
+ return -1;
+ }
+
+
+ /*
+ * Build the DHCP Discover
+ */
+ dhcp_discover_req (&call, sdl, &xid);
+
+ /*
+ * Expect a DHCP offer as response to DHCP discover
+ */
+ memcpy(expected_dhcp_payload, dhcp_magic_cookie, sizeof(dhcp_magic_cookie));
+ expected_dhcp_payload[sizeof(dhcp_magic_cookie) ]=0x35; /* DHCP */
+ expected_dhcp_payload[sizeof(dhcp_magic_cookie)+1]=0x01; /* Length : 1 */
+ expected_dhcp_payload[sizeof(dhcp_magic_cookie)+2]=0x02; /* DHCP_OFFER */
+
+ /*
+ * Send the Discover.
+ */
+ error = bootpc_call ((struct bootp_packet *)&call,
+ (struct bootp_packet *)&reply, procp,
+ expected_dhcp_payload, sizeof(expected_dhcp_payload));
+ if (error) {
+ printf ("BOOTP call failed -- %s\n", strerror(error));
+ soclose (so);
+ return -1;
+ }
+
+ /*
+ * Check for DHCP OFFER
+ */
+ if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) {
+ printf ("DHCP server did not send Magic Cookie.\n");
+ soclose (so);
+ return -1;
+ }
+
+ process_options (&reply.vend[4], sizeof (reply.vend) - 4);
+
+ if (dhcp_message_type != DHCP_OFFER) {
+ printf ("DHCP server did not send a DHCP Offer.\n");
+ soclose (so);
+ return -1;
+ }
+
+ /*
+ * Expect a DHCP_ACK as response to the DHCP REQUEST
+ * No need to reinitialize the whole expected_dhcp_payload variable,
+ * header and first two bytes of the payload are filled from DHCP offer
+ */
+ expected_dhcp_payload[sizeof(dhcp_magic_cookie)+2]=0x05; /* DHCP_ACK */
+
+ /*
+ * Send a DHCP REQUEST
+ */
+ dhcp_request_req (&call, &reply, sdl, true);
+
+ error = bootpc_call ((struct bootp_packet *)&call,
+ (struct bootp_packet *)&reply, procp,
+ expected_dhcp_payload, sizeof(expected_dhcp_payload));
+ if (error) {
+ printf ("BOOTP call failed -- %s\n", strerror(error));
+ soclose (so);
+ return -1;
+ }
+
+ /*
+ * Check for DHCP ACK/NACK
+ */
+ if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) != 0) {
+ printf ("DHCP server did not send Magic Cookie.\n");
+ soclose (so);
+ return -1;
+ }
+
+ process_options (&reply.vend[4], sizeof (reply.vend) - 4);
+
+ if (dhcp_message_type != DHCP_ACK) {
+ printf ("DHCP server did not accept the DHCP request\n");
+ soclose (so);
+ return -1;
+ }
+
+ /*
+ * Initialize network address structures
+ */
+ memset (&myaddr, 0, sizeof (myaddr));
+ memset (&dhcp_netmask, 0, sizeof (dhcp_netmask));
+ memset (&dhcp_gw, 0, sizeof (dhcp_gw));
+ myaddr.sin_len = sizeof (myaddr);
+ myaddr.sin_family = AF_INET;
+ dhcp_netmask.sin_len = sizeof (dhcp_netmask);
+ dhcp_netmask.sin_family = AF_INET;
+ dhcp_gw.sin_len = sizeof (dhcp_gw);
+ dhcp_gw.sin_family = AF_INET;
+
+ /*
+ * Set our address
+ */
+ myaddr.sin_addr = reply.yiaddr;
+
+ /*
+ * Process BOOTP/DHCP options
+ */
+ if (memcmp (&reply.vend[0], dhcp_magic_cookie, sizeof (dhcp_magic_cookie)) == 0)
+ process_options (&reply.vend[4], sizeof (reply.vend) - 4);
+
+ if (dhcp_option_overload & 1)
+ process_options ((unsigned char*) reply.file, sizeof reply.file);
+ else
+ if (reply.file[0])
+ rtems_bsdnet_bootp_boot_file_name = strdup (reply.file);
+
+ if (dhcp_option_overload & 2)
+ process_options ((unsigned char*) reply.sname, sizeof reply.sname);
+ else
+ if (reply.sname[0])
+ rtems_bsdnet_bootp_server_name = strdup (reply.sname);
+
+ /*
+ * Use defaults if values were not supplied by BOOTP/DHCP options
+ */
+ if (!dhcp_gotnetmask)
+ {
+ if (IN_CLASSA (ntohl (myaddr.sin_addr.s_addr)))
+ dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSA_NET);
+ else if (IN_CLASSB (ntohl (myaddr.sin_addr.s_addr)))
+ dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSB_NET);
+ else
+ dhcp_netmask.sin_addr.s_addr = htonl (IN_CLASSC_NET);
+ }
+
+ if (!dhcp_gotserver)
+ rtems_bsdnet_bootp_server_address = reply.siaddr;
+
+ if (!dhcp_gotgw)
+ dhcp_gw.sin_addr = reply.giaddr;
+
+ if (!dhcp_gotlogserver)
+ rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address;
+
+ printsetup (ifp->if_name, myaddr.sin_addr, dhcp_netmask.sin_addr,
+ rtems_bsdnet_bootp_server_address, dhcp_gw.sin_addr);
+
+ /*
+ * Update the files if we are asked too.
+ */
+ if (update_files) {
+ char *dn = rtems_bsdnet_domain_name;
+ char *hn = dhcp_hostname;
+ if (!dn)
+ dn = "mydomain";
+ if (!hn)
+ {
+ hn = "me";
+ sethostname (hn, strlen (hn));
+ }
+ rtems_rootfs_append_host_rec(myaddr.sin_addr.s_addr, hn, dn);
+
+ /*
+ * Should the given domainname be used here ?
+ */
+ if (dhcp_gotserver) {
+ if (rtems_bsdnet_bootp_server_name)
+ hn = rtems_bsdnet_bootp_server_name;
+ else
+ hn = "bootps";
+ rtems_rootfs_append_host_rec(rtems_bsdnet_bootp_server_address.s_addr,
+ hn, dn);
+ }
+
+ if (dhcp_gotlogserver) {
+ rtems_rootfs_append_host_rec(rtems_bsdnet_log_host_address.s_addr,
+ "logs", dn);
+ }
+
+ /*
+ * Setup the DNS configuration file /etc/resolv.conf.
+ */
+ if (rtems_bsdnet_nameserver_count) {
+ int i;
+ char buf[64];
+ const char *bufl[1];
+
+ bufl[0] = buf;
+
+#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH)
+
+ if (rtems_bsdnet_domain_name &&
+ (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) {
+ strcpy(buf, "search ");
+ strcat(buf, rtems_bsdnet_domain_name);
+ strcat(buf, "\n");
+ rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl);
+ }
+
+ for (i = 0; i < rtems_bsdnet_nameserver_count; i++) {
+ char addrbuf[INET_ADDRSTRLEN];
+ strcpy(buf, "nameserver ");
+ strcat(buf, inet_ntoa_r(rtems_bsdnet_ntpserver[i], addrbuf));
+ strcat(buf, "\n");
+ if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl))
+ break;
+ }
+ }
+ }
+
+ /*
+ * Configure the interface with the new settings
+ */
+ error = bootpc_adjust_interface (&ireq, so,
+ &myaddr, &dhcp_netmask, &dhcp_gw, procp);
+
+ /*
+ * Start the DHCP task if the lease isn't infinite.
+ */
+ if (dhcp_lease_time != 0xffffffff)
+ dhcp_start_task (sdl, &reply, 150);
+
+ soclose (so);
+
+ return 0;
+}
+
+/*
+ *
+ * RTEMS Entry point to DHCP client
+ *
+ */
+void rtems_bsdnet_do_dhcp (void)
+{
+ bool update = true;
+ rtems_bsdnet_semaphore_obtain ();
+ while( dhcp_init (update) < 0 ) {
+ update = false;
+ rtems_bsdnet_semaphore_release();
+ rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(1000));
+ rtems_bsdnet_semaphore_obtain ();
+ }
+ rtems_bsdnet_semaphore_release ();
+}
+
+int rtems_bsdnet_do_dhcp_timeout( void )
+{
+ int return_value;
+
+ rtems_bsdnet_semaphore_obtain ();
+ return_value = dhcp_init (false);
+ rtems_bsdnet_semaphore_release ();
+
+ return return_value;
+}
+
+void rtems_bsdnet_dhcp_down (void)
+{
+ if(dhcp_task_id != 0) {
+ rtems_event_send (dhcp_task_id, RTEMS_EVENT_0);
+ }
+}
+
+void
+rtems_bsdnet_do_dhcp_refresh_only (unsigned long xid,
+ unsigned long lease_time,
+ unsigned long elapsed_time,
+ unsigned long ip_address,
+ unsigned long srv_address,
+ const char* hostname)
+{
+ struct dhcp_packet reply;
+ struct ifnet *ifp = NULL;
+ struct ifaddr *ifa = NULL;
+ struct sockaddr_dl *sdl = NULL;
+ struct sockaddr_in *sin = NULL;
+ int match = 0;
+ struct ifnet *mtif = NULL;
+
+ /*
+ * If an infinite lease has been granted, no task is needed.
+ */
+ if (lease_time == 0xffffffff)
+ return;
+
+ /*
+ * Find a network interface.
+ */
+ for (ifp = ifnet; (ifp != NULL) && !match; ifp = ifp->if_next)
+ if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ {
+ sin = (struct sockaddr_in *) ifa->ifa_addr;
+ if (sin->sin_addr.s_addr == htonl (ip_address))
+ {
+ mtif = ifp;
+ match = 1;
+ break;
+ }
+ }
+
+ if (!match) {
+ printf ("dhcpc: no matching interface\n");
+ return;
+ }
+
+ for (ifa = mtif->if_addrlist; ifa != NULL; ifa = ifa->ifa_next)
+ if (ifa->ifa_addr->sa_family == AF_LINK &&
+ (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
+ sdl->sdl_type == IFT_ETHER)
+ break;
+
+ if (!match) {
+ printf ("dhcpc: no matching interface address\n");
+ return;
+ }
+
+ /*
+ * Set up given values in a simulated DHCP reply.
+ */
+ memset (&reply, 0x00, sizeof (reply));
+ reply.xid = htonl (xid);
+ reply.yiaddr.s_addr = htonl (ip_address);
+ reply.siaddr.s_addr = htonl (srv_address);
+ if (reply.siaddr.s_addr != rtems_bsdnet_bootp_server_address.s_addr)
+ {
+ memcpy (&rtems_bsdnet_bootp_server_address, &reply.siaddr,
+ sizeof (reply.siaddr));
+ }
+
+ dhcp_lease_time = lease_time;
+ dhcp_elapsed_time = elapsed_time;
+
+ if (hostname)
+ {
+ sethostname ((char *) hostname, strlen (hostname));
+ dhcp_hostname = bootp_strdup_realloc (dhcp_hostname, hostname);
+ }
+
+ dhcp_start_task (sdl, &reply, 150);
+}
diff --git a/rtems/rtems_dhcp_failsafe.c b/rtems/rtems_dhcp_failsafe.c
new file mode 100644
index 0000000..65c107d
--- /dev/null
+++ b/rtems/rtems_dhcp_failsafe.c
@@ -0,0 +1,380 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ Description: Wrapper around DHCP client to restart it when the interface
+ moves to another network.
+
+ Authors: Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind
+ Maarten Van Es <maarten@mind.be>, Essensium/Mind
+ (C) Septentrio 2008
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution or at
+ http://www.rtems.org/license/LICENSE.
+
+
+ To use this functionality, call rtems_bsdnet_do_dhcp_failsafe() or set it
+ as the bootp member of the rtems_bsdnet_config structure.
+
+ The rtems_bsdnet_do_dhcp_failsafe() function provides the following
+ functionalities:
+
+ * It starts DHCP on the first non-loopback, non-point-to-point interface.
+ Before DHCP is started, any existing IP address on that interface is
+ removed, as well as the default route.
+
+ * If DHCP fails to acquire an address for whatever reason, the interface
+ is reconfigured with the static address provided in its
+ rtems_bsdnet_ifconfig structure, and the default route from
+ rtems_bsdnet_config is restored.
+ It is possible to change the address in the rtems_bsdnet_ifconfig structure
+ while the system is running.
+
+ * Optionally, after the interface is configured (either with DHCP or
+ statically), a task is started to monitor it. When the interface remains
+ disconnected (i.e. its IFF_RUNNING flag is off) for network_fail_timeout
+ seconds, the dhcp lease renewal is stopped. As soon as the interface is
+ connected again, DHCP is started again as above.
+ If network_fail_timeout is set to 0, the monitor task is not started.
+
+ * Optionally, when the interface is disconnected, it is also brought down
+ for network_down_time seconds. Since this possibly makes the IFF_RUNNING
+ flag unuseable, the interface is brought up again before the flag is
+ polled.
+ If network_down_time is set to 0, the interface is not brought down.
+
+ * Optionally, before DHCP is started, we wait for broadcast_delay seconds.
+ This is necessary to allow some routers to perform spanning tree discovery.
+
+ Note that DHCP doesn't work well with multiple interfaces: only one of them
+ is configured using DHCP, and we can't guarantee it's the same one that is
+ monitored by this function.
+
+*/
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_bsdnet_internal.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <rtems/dhcp.h>
+#include <rtems/rtems_dhcp_failsafe.h>
+
+struct proc; /* Unused parameter of some functions. */
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <netinet/in.h> /* for sockaddr_in */
+#include <net/if.h> /* for if.h */
+#include <net/if_var.h> /* for in_var.h */
+#include <netinet/in_var.h> /* for in_aliasreq */
+#include <sys/sockio.h> /* for ioctl definitions */
+
+static int network_fail_timeout = RTEMS_DHCP_FAILSAFE_NETWORK_FAIL_TIMEOUT;
+static int network_down_time = RTEMS_DHCP_FAILSAFE_NETWORK_DOWN_TIME;
+static int broadcast_delay = RTEMS_DHCP_FAILSAFE_BROADCAST_DELAY;
+static int dhcp_monitor_priority = RTEMS_DHCP_FAILSAFE_DHCP_MONITOR_PRIORITY;
+
+void rtems_bsdnet_dhcp_failsafe_config(
+ int network_fail_timeout_,
+ int network_down_time_,
+ int broadcast_delay_,
+ int dhcp_monitor_priority_
+)
+{
+ network_fail_timeout = network_fail_timeout_;
+ network_down_time = network_down_time_;
+ broadcast_delay = broadcast_delay_;
+ dhcp_monitor_priority = dhcp_monitor_priority_;
+}
+
+/*
+ * returns 0 when successful, negative value for failure
+ */
+static int remove_address(const char *if_name)
+{
+ struct sockaddr_in address;
+ struct in_aliasreq ifra;
+ int retval = 0;
+
+ memset (&address, '\0', sizeof (address));
+ address.sin_len = sizeof (address);
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+
+ /* Remove old default route to 0.0.0.0 */
+ if (rtems_bsdnet_rtrequest (RTM_DELETE, (struct sockaddr *)&address, NULL,
+ (struct sockaddr *)&address,
+ (RTF_UP | RTF_STATIC), NULL) < 0 ) {
+ printf ("Failed to delete default route: %s (%d)\n", strerror (errno), errno);
+ retval = -1;
+ }
+
+ /* Remove old ip-address */
+ if (rtems_bsdnet_ifconfig(if_name, SIOCGIFADDR, &address) < 0) {
+ printf ("Failed to get if address: %s (%d)\n", strerror (errno), errno);
+ return -1;
+ }
+
+ strncpy (ifra.ifra_name, if_name, IFNAMSIZ);
+ memcpy (&ifra.ifra_addr, &address, sizeof(address));
+ if (rtems_bsdnet_ifconfig(if_name, SIOCDIFADDR, &ifra)) {
+ printf ("Can't delete if address: %s (%d)\n", strerror (errno), errno);
+ return -1;
+ }
+
+ return retval;
+}
+
+
+static int
+dhcp_if_down (const char* ifname)
+{
+ int16_t flags;
+ if (rtems_bsdnet_ifconfig (ifname, SIOCGIFFLAGS, &flags) < 0) {
+ printf ("Can't get flags for %s: %s\n", ifname, strerror (errno));
+ return -1;
+ }
+ if (flags & IFF_UP) {
+ flags &= ~IFF_UP;
+ if (rtems_bsdnet_ifconfig (ifname, SIOCSIFFLAGS, &flags) < 0) {
+ printf ("Can't bring %s down: %s\n", ifname, strerror (errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+dhcp_if_up (const char* ifname)
+{
+ int16_t flags;
+ if (rtems_bsdnet_ifconfig (ifname, SIOCGIFFLAGS, &flags) < 0) {
+ printf ("Can't get flags for %s: %s\n", ifname, strerror (errno));
+ return -1;
+ }
+ if (!(flags & IFF_UP)) {
+ flags |= IFF_UP;
+ if (rtems_bsdnet_ifconfig (ifname, SIOCSIFFLAGS, &flags) < 0) {
+ printf ("Can't bring %s up: %s\n", ifname, strerror (errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+set_static_address (struct rtems_bsdnet_ifconfig *ifp)
+{
+ int16_t flags;
+ struct sockaddr_in address;
+ struct sockaddr_in netmask;
+ struct sockaddr_in broadcast;
+ struct sockaddr_in gateway;
+
+ if (ifp->ip_address != NULL) {
+ printf("Setting static address for interface %s.\n", ifp->name);
+
+ /*
+ * Bring interface up
+ */
+ if (dhcp_if_up (ifp->name) < 0)
+ return -1;
+
+ /*
+ * Set interface netmask
+ */
+ memset (&netmask, '\0', sizeof netmask);
+ netmask.sin_len = sizeof netmask;
+ netmask.sin_family = AF_INET;
+ netmask.sin_addr.s_addr = inet_addr (ifp->ip_netmask);
+ if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFNETMASK, &netmask) < 0) {
+ printf ("Can't set %s netmask: %s\n", ifp->name, strerror (errno));
+ return -1;
+ }
+
+ /*
+ * Set interface address
+ */
+ memset (&address, '\0', sizeof address);
+ address.sin_len = sizeof address;
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = inet_addr (ifp->ip_address);
+ if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFADDR, &address) < 0) {
+ printf ("Can't set %s address: %s\n", ifp->name, strerror (errno));
+ return -1;
+ }
+
+ /*
+ * Set interface broadcast address if the interface has the
+ * broadcast flag set.
+ */
+ if (rtems_bsdnet_ifconfig (ifp->name, SIOCGIFFLAGS, &flags) < 0) {
+ printf ("Can't read %s flags: %s\n", ifp->name, strerror (errno));
+ return -1;
+ }
+ if (flags & IFF_BROADCAST) {
+ memset (&broadcast, '\0', sizeof broadcast);
+ broadcast.sin_len = sizeof broadcast;
+ broadcast.sin_family = AF_INET;
+ broadcast.sin_addr.s_addr = address.sin_addr.s_addr | ~netmask.sin_addr.s_addr;
+
+ if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFBRDADDR, &broadcast) < 0) {
+ struct in_addr in_addr;
+ char buf[20];
+
+ in_addr.s_addr = broadcast.sin_addr.s_addr;
+ if (!inet_ntop (AF_INET, &in_addr, buf, sizeof (buf)))
+ strcpy (buf, "?.?.?.?");
+ printf ("Can't set %s broadcast address %s: %s\n", ifp->name, buf, strerror (errno));
+ }
+ }
+ }
+
+ /*
+ * Set default route
+ */
+ if (rtems_bsdnet_config.gateway) {
+ address.sin_addr.s_addr = INADDR_ANY;
+ netmask.sin_addr.s_addr = INADDR_ANY;
+ memset (&gateway, '\0', sizeof gateway);
+ gateway.sin_len = sizeof gateway;
+ gateway.sin_family = AF_INET;
+ gateway.sin_addr.s_addr = inet_addr (rtems_bsdnet_config.gateway);
+
+ if (rtems_bsdnet_rtrequest (RTM_ADD,
+ (struct sockaddr *) &address,
+ (struct sockaddr *) &gateway,
+ (struct sockaddr *) &netmask,
+ (RTF_UP | RTF_GATEWAY | RTF_STATIC),
+ NULL
+ ) < 0) {
+ printf ("Can't set default route: %s\n", strerror (errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+do_dhcp_init (struct rtems_bsdnet_ifconfig *ifp)
+{
+ if (broadcast_delay) {
+ /* Wait before sending broadcast. */
+ rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(broadcast_delay * 1000));
+ }
+
+ printf ("starting dhcp client...\n");
+
+ remove_address(ifp->name);
+ if (rtems_bsdnet_do_dhcp_timeout () != 0) {
+ remove_address(ifp->name);
+ set_static_address (ifp); /* use static ip-address if dhcp failed */
+ }
+
+}
+
+/*
+ * Main dhcp monitor thread
+ */
+static void dhcp_monitor_task (rtems_task_argument ifp_arg)
+{
+ struct rtems_bsdnet_ifconfig *ifp = (struct rtems_bsdnet_ifconfig *)ifp_arg;
+ char *ifname = ifp->name;
+ unsigned int downcount = 0;
+ int16_t ifflags;
+ int must_renew = FALSE;
+
+ while (TRUE) {
+ if (rtems_bsdnet_ifconfig(ifname, SIOCGIFFLAGS, &ifflags) < 0) {
+ printf ("Failed to get if flags: %s (%d)\n", strerror (errno), errno);
+ goto error_out;
+ }
+
+ if ((ifflags & IFF_RUNNING) != 0) {
+ if(must_renew) {
+ must_renew = FALSE;
+ do_dhcp_init(ifp);
+ }
+ downcount = 0;
+ } else {
+ if (downcount < network_fail_timeout) {
+ downcount++;
+
+ if (downcount == network_fail_timeout) {
+ printf ("lost network connection...\n");
+ rtems_bsdnet_dhcp_down ();
+ must_renew = TRUE;
+ dhcp_if_down(ifname);
+ rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(network_down_time * 1000));
+ dhcp_if_up(ifname);
+ downcount = 0;
+ }
+ }
+ }
+
+ rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(1000));
+ }
+
+error_out:
+ printf("Stopping dhcp monitoring application.\n");
+ rtems_task_exit();
+}
+
+/*
+* initialize dhcp monitoring application
+* start dhcp monitoring thread
+*/
+void rtems_bsdnet_do_dhcp_failsafe (void)
+{
+ rtems_status_code sc;
+ rtems_id id;
+ struct rtems_bsdnet_ifconfig *ifp;
+ int16_t ifflags;
+
+ /* Find a suitable interface */
+ for (ifp = rtems_bsdnet_config.ifconfig; ifp; ifp = ifp->next) {
+ if (rtems_bsdnet_ifconfig (ifp->name, SIOCGIFFLAGS, &ifflags) < 0)
+ continue;
+ if ((ifflags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
+ break;
+ }
+ if (ifp == NULL){
+ printf ("dhcpc_failsafe: no suitable interface\n");
+ return;
+ }
+ printf("starting dhcp on interface %s\n", ifp->name);
+ do_dhcp_init(ifp);
+
+ if (network_fail_timeout) {
+ sc = rtems_task_create (rtems_build_name ('d','h','c','m'),
+ dhcp_monitor_priority,
+ 2048,
+ RTEMS_PREEMPT |
+ RTEMS_NO_TIMESLICE |
+ RTEMS_NO_ASR |
+ RTEMS_INTERRUPT_LEVEL (0),
+ RTEMS_LOCAL,
+ &id);
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Failed to create dhcp monitor task, code %d\n", sc);
+ return;
+ }
+
+ sc = rtems_task_start (id, dhcp_monitor_task, (rtems_task_argument) ifp);
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Failed to start dhcp monitor task, code %d\n", sc);
+ }
+ }
+}
+
diff --git a/rtems/rtems_dhcp_failsafe.h b/rtems/rtems_dhcp_failsafe.h
new file mode 100644
index 0000000..3c5a59f
--- /dev/null
+++ b/rtems/rtems_dhcp_failsafe.h
@@ -0,0 +1,64 @@
+/*
+ Description: Wrapper around DHCP client to restart it when the interface
+ moves to another network.
+
+ Authors: Arnout Vandecappelle <arnout@mind.be>, Essensium/Mind
+ Maarten Van Es <maarten@mind.be>, Essensium/Mind
+ (C) Septentrio 2008
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution or at
+ http://www.rtems.org/license/LICENSE.
+*/
+
+#ifndef _RTEMS_DHCP_FAILSAFE_H_
+#define _RTEMS_DHCP_FAILSAFE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Default settings for the DHCP failsafe. They can be overridden
+ * using rtems_bsdnet_dhcp_failsafe_config(); see that for descriptions.
+ */
+#ifndef RTEMS_DHCP_FAILSAFE_NETWORK_FAIL_TIMEOUT
+#define RTEMS_DHCP_FAILSAFE_NETWORK_FAIL_TIMEOUT 5
+#endif
+
+#ifndef RTEMS_DHCP_FAILSAFE_NETWORK_DOWN_TIME
+#define RTEMS_DHCP_FAILSAFE_NETWORK_DOWN_TIME 30
+#endif
+
+#ifndef RTEMS_DHCP_FAILSAFE_BROADCAST_DELAY
+#define RTEMS_DHCP_FAILSAFE_BROADCAST_DELAY 0
+#endif
+
+#ifndef RTEMS_DHCP_FAILSAFE_DHCP_MONITOR_PRIORITY
+#define RTEMS_DHCP_FAILSAFE_DHCP_MONITOR_PRIORITY 250
+#endif
+
+
+void rtems_bsdnet_do_dhcp_failsafe (void);
+
+/** Set the DHCP fallback options. See the commentary at the top of the
+ * implementation.
+ @note Some of these options can be compile-time disabled - see the code.
+ */
+void rtems_bsdnet_dhcp_failsafe_config(
+ int network_fail_timeout, /**< The number of seconds before the interface is
+ * considered disconnected
+ */
+ int network_down_time, /**< The number of seconds the interface
+ * remains down.
+ */
+ int broadcast_delay, /**< The delay in seconds before broadcasts
+ * are sent.
+ */
+ int dhcp_monitor_priority /**< The monitor priority.*/
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/rtems/rtems_glue.c b/rtems/rtems_glue.c
new file mode 100644
index 0000000..ee6c8f5
--- /dev/null
+++ b/rtems/rtems_glue.c
@@ -0,0 +1,1264 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define RTEMS_FAST_MUTEX
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/error.h>
+#include <rtems/thread.h>
+#include <rtems/rtems_bsdnet.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/domain.h>
+#include <sys/mbuf.h>
+#include <sys/socketvar.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/callout.h>
+#include <sys/proc.h>
+#include <sys/sockio.h>
+#include <sys/systm.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <vm/vm.h>
+
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include "loop.h"
+
+/*
+ * Memory allocation
+ */
+static uint32_t nmbuf = (64L * 1024L) / _SYS_MBUF_LEGACY_MSIZE;
+ uint32_t nmbclusters = (128L * 1024L) / MCLBYTES;
+
+/*
+ * Network task synchronization
+ */
+static rtems_recursive_mutex networkMutex =
+ RTEMS_RECURSIVE_MUTEX_INITIALIZER("_Network");
+static rtems_id networkDaemonTid;
+static uint32_t networkDaemonPriority;
+#ifdef RTEMS_SMP
+static const cpu_set_t *networkDaemonCpuset = 0;
+static size_t networkDaemonCpusetSize = 0;
+#endif
+static void networkDaemon (void *task_argument);
+
+/*
+ * Network timing
+ */
+int rtems_bsdnet_ticks_per_second;
+int rtems_bsdnet_microseconds_per_tick;
+
+/*
+ * Callout processing
+ */
+static rtems_interval ticksWhenCalloutsLastChecked;
+struct callout *callfree = NULL;
+struct callout calltodo;
+
+/*
+ * FreeBSD variables
+ */
+int nfs_diskless_valid;
+
+/*
+ * BOOTP values
+ */
+struct in_addr rtems_bsdnet_log_host_address = {0};
+struct in_addr rtems_bsdnet_bootp_server_address = {0};
+char *rtems_bsdnet_bootp_boot_file_name = 0;
+char *rtems_bsdnet_bootp_server_name = 0;
+char *rtems_bsdnet_domain_name = 0;
+char *rtems_bsdnet_bootp_cmdline = 0;
+static struct in_addr _rtems_bsdnet_nameserver[sizeof rtems_bsdnet_config.name_server /
+ sizeof rtems_bsdnet_config.name_server[0]];
+struct in_addr *rtems_bsdnet_nameserver = _rtems_bsdnet_nameserver;
+int rtems_bsdnet_nameserver_count = 0;
+static struct in_addr _rtems_bsdnet_ntpserver[sizeof rtems_bsdnet_config.ntp_server /
+ sizeof rtems_bsdnet_config.ntp_server[0]];
+struct in_addr *rtems_bsdnet_ntpserver = _rtems_bsdnet_ntpserver;
+int rtems_bsdnet_ntpserver_count = 0;
+int32_t rtems_bsdnet_timeoffset = 0;
+
+static const struct sockaddr_in address_template = {
+ sizeof(address_template),
+ AF_INET,
+ 0,
+ { INADDR_ANY },
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static void
+rtems_bsdnet_initialize_sockaddr_in(struct sockaddr_in *addr)
+{
+ memcpy(addr, &address_template, sizeof(*addr));
+}
+
+uint32_t
+rtems_bsdnet_semaphore_release_recursive(void)
+{
+ uint32_t nest_count;
+
+ nest_count = networkMutex._nest_level;
+ networkMutex._nest_level = 0;
+ rtems_recursive_mutex_unlock(&networkMutex);
+ return nest_count;
+}
+
+void
+rtems_bsdnet_semaphore_obtain_recursive(uint32_t nest_count)
+{
+ rtems_recursive_mutex_lock(&networkMutex);
+ networkMutex._nest_level = nest_count;
+}
+
+/*
+ * Perform FreeBSD memory allocation.
+ * FIXME: This should be modified to keep memory allocation statistics.
+ */
+#undef malloc
+#undef free
+extern void *malloc (size_t);
+extern void free (void *);
+void *
+rtems_bsdnet_malloc (size_t size, int type, int flags)
+{
+ void *p;
+ int try = 0;
+
+ for (;;) {
+ uint32_t nest_count;
+
+ p = malloc (size);
+ if (p || (flags & M_NOWAIT))
+ return p;
+ nest_count = rtems_bsdnet_semaphore_release_recursive ();
+ if (++try >= 30) {
+ rtems_bsdnet_malloc_starvation();
+ try = 0;
+ }
+ rtems_task_wake_after (rtems_bsdnet_ticks_per_second);
+ rtems_bsdnet_semaphore_obtain_recursive (nest_count);
+ }
+}
+
+/*
+ * Free FreeBSD memory
+ * FIXME: This should be modified to keep memory allocation statistics.
+ */
+void
+rtems_bsdnet_free (void *addr, int type)
+{
+ free (addr);
+}
+
+/*
+ * Externs for BSD data we have to access during initialization
+ */
+extern struct domain routedomain;
+extern struct domain inetdomain;
+
+/*
+ * Do the initializations required by the BSD code
+ */
+static int
+bsd_init (void)
+{
+ int i;
+ char *p;
+
+ /*
+ * Set up mbuf cluster data strutures
+ */
+ p = rtems_bsdnet_malloc_mbuf ((nmbclusters*MCLBYTES)+MCLBYTES-1, MBUF_MALLOC_NMBCLUSTERS);
+ if (p == NULL) {
+ printf ("Can't get network cluster memory.\n");
+ return -1;
+ }
+ p = (char *)(((intptr_t)p + (MCLBYTES-1)) & ~(MCLBYTES-1));
+ mbutl = (struct mbuf *)p;
+ for (i = 0; i < nmbclusters; i++) {
+ ((union mcluster *)p)->mcl_next = mclfree;
+ mclfree = (union mcluster *)p;
+ p += MCLBYTES;
+ mbstat.m_clfree++;
+ }
+ mbstat.m_clusters = nmbclusters;
+ mclrefcnt = rtems_bsdnet_malloc_mbuf (nmbclusters, MBUF_MALLOC_MCLREFCNT);
+ if (mclrefcnt == NULL) {
+ printf ("Can't get mbuf cluster reference counts memory.\n");
+ return -1;
+ }
+ memset (mclrefcnt, '\0', nmbclusters);
+
+ /*
+ * Set up mbuf data structures
+ */
+
+ p = rtems_bsdnet_malloc_mbuf(nmbuf * _SYS_MBUF_LEGACY_MSIZE + _SYS_MBUF_LEGACY_MSIZE - 1,MBUF_MALLOC_MBUF);
+ p = (char *)(((uintptr_t)p + _SYS_MBUF_LEGACY_MSIZE - 1) & ~(_SYS_MBUF_LEGACY_MSIZE - 1));
+ if (p == NULL) {
+ printf ("Can't get network memory.\n");
+ return -1;
+ }
+ for (i = 0; i < nmbuf; i++) {
+ ((struct mbuf *)p)->m_next = mmbfree;
+ mmbfree = (struct mbuf *)p;
+ p += _SYS_MBUF_LEGACY_MSIZE;
+ }
+ mbstat.m_mbufs = nmbuf;
+ mbstat.m_mtypes[MT_FREE] = nmbuf;
+
+ /*
+ * Set up domains
+ */
+ {
+
+ routedomain.dom_next = domains;
+ domains = &routedomain;
+ inetdomain.dom_next = domains;
+ domains = &inetdomain;
+ domaininit (NULL);
+ }
+
+ /*
+ * Setup the sysctl, normally done by a SYSINIT call.
+ */
+ sysctl_register_all(0);
+
+ /*
+ * Set up interfaces
+ */
+ ifinit (NULL);
+ return 0;
+}
+
+/*
+ * Initialize and start network operations
+ */
+static int
+rtems_bsdnet_initialize (void)
+{
+ rtems_bsdnet_semaphore_obtain ();
+
+ /*
+ * Set the priority of all network tasks
+ */
+ if (rtems_bsdnet_config.network_task_priority == 0)
+ networkDaemonPriority = 100;
+#ifdef RTEMS_MULTIPROCESSING
+ /*
+ * Allow network tasks to run with priority 0 (PRIORITY_PSEUDO_ISR) using
+ * UINT32_MAX for the network task priority in the network configuration.
+ * This enables MPCI via a TCP/IP network.
+ */
+ else if (rtems_bsdnet_config.network_task_priority != UINT32_MAX)
+#else
+ else
+#endif
+ networkDaemonPriority = rtems_bsdnet_config.network_task_priority;
+
+ /*
+ * Default network task CPU affinity
+ */
+#ifdef RTEMS_SMP
+ networkDaemonCpuset = rtems_bsdnet_config.network_task_cpuset;
+ networkDaemonCpusetSize = rtems_bsdnet_config.network_task_cpuset_size;
+#endif
+
+ /*
+ * Set the memory allocation limits
+ */
+ if (rtems_bsdnet_config.mbuf_bytecount)
+ nmbuf = rtems_bsdnet_config.mbuf_bytecount / _SYS_MBUF_LEGACY_MSIZE;
+ if (rtems_bsdnet_config.mbuf_cluster_bytecount)
+ nmbclusters = rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES;
+
+ rtems_set_udp_buffer_sizes(
+ rtems_bsdnet_config.udp_tx_buf_size,
+ rtems_bsdnet_config.udp_rx_buf_size
+ );
+
+ rtems_set_tcp_buffer_sizes(
+ rtems_bsdnet_config.tcp_tx_buf_size,
+ rtems_bsdnet_config.tcp_rx_buf_size
+ );
+
+ rtems_set_sb_efficiency( rtems_bsdnet_config.sb_efficiency );
+
+ /*
+ * Compute clock tick conversion factors
+ */
+ rtems_bsdnet_ticks_per_second = rtems_clock_get_ticks_per_second();
+ if (rtems_bsdnet_ticks_per_second <= 0)
+ rtems_bsdnet_ticks_per_second = 1;
+ rtems_bsdnet_microseconds_per_tick =
+ 1000000 / rtems_bsdnet_ticks_per_second;
+
+ /*
+ * Set up BSD-style sockets
+ */
+ if (bsd_init () < 0) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+
+ /*
+ * Start network daemon
+ */
+ networkDaemonTid = rtems_bsdnet_newproc ("ntwk", 4096, networkDaemon, NULL);
+
+ /*
+ * Let other network tasks begin
+ */
+ rtems_bsdnet_semaphore_release ();
+
+ rtems_bsdnet_initialize_loop();
+
+ return 0;
+}
+
+/*
+ * Obtain network mutex
+ */
+void
+rtems_bsdnet_semaphore_obtain (void)
+{
+ rtems_recursive_mutex_lock(&networkMutex);
+}
+
+/*
+ * Release network mutex
+ */
+void
+rtems_bsdnet_semaphore_release (void)
+{
+ rtems_recursive_mutex_unlock(&networkMutex);
+}
+
+static int
+rtems_bsdnet_sleep(rtems_event_set in, rtems_interval ticks)
+{
+ rtems_status_code sc;
+ rtems_event_set out;
+ rtems_event_set out2;
+
+ in |= RTEMS_EVENT_SYSTEM_NETWORK_CLOSE;
+
+ /*
+ * Soak up any pending events. The sleep/wakeup synchronization in the
+ * FreeBSD kernel has no memory.
+ */
+ rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
+ RTEMS_NO_TIMEOUT, &out);
+
+ /*
+ * Wait for the wakeup event.
+ */
+ sc = rtems_bsdnet_event_receive(in, RTEMS_EVENT_ANY | RTEMS_WAIT,
+ ticks, &out);
+
+ /*
+ * Get additional events that may have been received between the
+ * rtems_event_system_receive() and the rtems_bsdnet_semaphore_obtain().
+ */
+ rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
+ RTEMS_NO_TIMEOUT, &out2);
+ out |= out2;
+
+ if (out & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE)
+ return (ENXIO);
+
+ if (sc == RTEMS_SUCCESSFUL)
+ return (0);
+
+ return (EWOULDBLOCK);
+}
+
+/*
+ * Wait for something to happen to a socket buffer
+ */
+int
+sbwait(struct sockbuf *sb)
+{
+ int error;
+
+ /*
+ * Set this task as the target of the wakeup operation.
+ */
+ sb->sb_sel.si_pid = rtems_task_self();
+
+ /*
+ * Show that socket is waiting
+ */
+ sb->sb_flags |= SB_WAIT;
+
+ error = rtems_bsdnet_sleep(SBWAIT_EVENT, sb->sb_timeo);
+ if (error != ENXIO)
+ sb->sb_flags &= ~SB_WAIT;
+
+ return (error);
+}
+
+
+/*
+ * Wake up the task waiting on a socket buffer.
+ */
+void
+sowakeup(
+ struct socket *so,
+ struct sockbuf *sb)
+{
+ if (sb->sb_flags & SB_WAIT) {
+ rtems_event_system_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
+ }
+ if (sb->sb_wakeup) {
+ (*sb->sb_wakeup) (so, sb->sb_wakeuparg);
+ }
+}
+
+/*
+ * For now, a socket can be used by only one task at a time.
+ */
+int
+sb_lock(struct sockbuf *sb)
+{
+ rtems_panic ("Socket buffer is already in use.");
+ return 0;
+}
+void
+wakeup (void *p)
+{
+ rtems_panic ("Wakeup called");
+}
+
+/*
+ * Wait for a connection/disconnection event.
+ */
+int
+soconnsleep (struct socket *so)
+{
+ int error;
+
+ /*
+ * Set this task as the target of the wakeup operation.
+ */
+ if (so->so_pgid)
+ rtems_panic ("Another task is already sleeping on that socket");
+ so->so_pgid = rtems_task_self();
+
+ error = rtems_bsdnet_sleep(SOSLEEP_EVENT, so->so_rcv.sb_timeo);
+ if (error != ENXIO)
+ so->so_pgid = 0;
+
+ return (error);
+}
+
+/*
+ * Wake up a task waiting for a connection/disconnection to complete.
+ */
+void
+soconnwakeup (struct socket *so)
+{
+ if (so->so_pgid)
+ rtems_event_system_send (so->so_pgid, SOSLEEP_EVENT);
+}
+
+/*
+ * Send an event to the network daemon.
+ * This corresponds to sending a software interrupt in the BSD kernel.
+ */
+void
+rtems_bsdnet_schednetisr (int n)
+{
+ rtems_event_system_send (networkDaemonTid, 1 << n);
+}
+
+/*
+ * The network daemon
+ * This provides a context to run BSD software interrupts
+ */
+static void
+networkDaemon (void *task_argument)
+{
+ rtems_status_code sc;
+ rtems_event_set events;
+ rtems_interval now;
+ int ticksPassed;
+ uint32_t timeout;
+ struct callout *c;
+
+ for (;;) {
+ c = calltodo.c_next;
+ if (c)
+ timeout = c->c_time;
+ else
+ timeout = RTEMS_NO_TIMEOUT;
+
+ sc = rtems_bsdnet_event_receive (NETISR_EVENTS,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ timeout,
+ &events);
+ if ( sc == RTEMS_SUCCESSFUL ) {
+ if (events & NETISR_IP_EVENT)
+ ipintr ();
+ if (events & NETISR_ARP_EVENT)
+ arpintr ();
+ }
+
+ now = rtems_clock_get_ticks_since_boot();
+ ticksPassed = now - ticksWhenCalloutsLastChecked;
+ if (ticksPassed != 0) {
+ ticksWhenCalloutsLastChecked = now;
+
+ c = calltodo.c_next;
+ if (c) {
+ c->c_time -= ticksPassed;
+ while ((c = calltodo.c_next) != NULL && c->c_time <= 0) {
+ void *arg;
+ void (*func) (void *);
+
+ func = c->c_func;
+ arg = c->c_arg;
+ calltodo.c_next = c->c_next;
+ c->c_next = callfree;
+ callfree = c;
+ (*func)(arg);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Structure passed to task-start stub
+ */
+struct newtask {
+ void (*entry)(void *);
+ void *arg;
+};
+
+/*
+ * Task-start stub
+ */
+static void
+taskEntry (rtems_task_argument arg)
+{
+ struct newtask t;
+
+ /*
+ * Pick up task information and free
+ * the memory allocated to pass the
+ * information to this task.
+ */
+ t = *(struct newtask *)arg;
+ free ((struct newtask *)arg);
+
+ /*
+ * Enter the competition for the network semaphore
+ */
+ rtems_bsdnet_semaphore_obtain ();
+
+ /*
+ * Enter the task
+ */
+ (*t.entry)(t.arg);
+ rtems_panic ("Network task returned!\n");
+}
+
+
+/*
+ * Start a network task
+ */
+#ifdef RTEMS_SMP
+rtems_id
+rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
+{
+ return rtems_bsdnet_newproc_affinity( name, stacksize, entry, arg,
+ networkDaemonCpuset, networkDaemonCpusetSize );
+}
+
+rtems_id
+rtems_bsdnet_newproc_affinity (char *name, int stacksize, void(*entry)(void *),
+ void *arg, const cpu_set_t *set, const size_t setsize)
+#else
+rtems_id
+rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
+#endif
+{
+ struct newtask *t;
+ char nm[4];
+ rtems_id tid;
+ rtems_status_code sc;
+
+ strncpy (nm, name, 4);
+ sc = rtems_task_create (rtems_build_name(nm[0], nm[1], nm[2], nm[3]),
+ networkDaemonPriority,
+ stacksize,
+ RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
+#ifdef RTEMS_MULTIPROCESSING
+ RTEMS_SYSTEM_TASK |
+#endif
+ RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
+ &tid);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't create network daemon `%s': `%s'\n", name, rtems_status_text (sc));
+
+#ifdef RTEMS_SMP
+ /*
+ * Use the default affinity or use the user-provided CPU set
+ */
+ if ( set != 0 )
+ rtems_task_set_affinity( tid, setsize, set );
+#endif
+
+ /*
+ * Set up task arguments
+ */
+ t = malloc (sizeof *t);
+ t->entry = entry;
+ t->arg = arg;
+
+ /*
+ * Start the task
+ */
+ sc = rtems_task_start (tid, taskEntry, (rtems_task_argument)t);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't start network daemon `%s': `%s'\n", name, rtems_status_text (sc));
+
+ /*
+ * Let our caller know the i.d. of the new task
+ */
+ return tid;
+}
+
+rtems_status_code rtems_bsdnet_event_receive (
+ rtems_event_set event_in,
+ rtems_option option_set,
+ rtems_interval ticks,
+ rtems_event_set *event_out)
+{
+ rtems_status_code sc;
+
+ rtems_bsdnet_semaphore_release ();
+ sc = rtems_event_system_receive (event_in, option_set, ticks, event_out);
+ rtems_bsdnet_semaphore_obtain ();
+ return sc;
+}
+
+/*
+ * Fake random number generator
+ */
+unsigned long
+rtems_bsdnet_random (void)
+{
+ rtems_interval now;
+
+ now = rtems_clock_get_ticks_since_boot();
+ return (now * 99991);
+}
+
+/*
+ * Callout list processing
+ */
+void
+rtems_bsdnet_timeout(void (*ftn)(void *), void *arg, int ticks)
+{
+ register struct callout *new, *p, *t;
+
+ if (ticks <= 0)
+ ticks = 1;
+
+ /* Fill in the next free callout structure. */
+ if (callfree == NULL) {
+ callfree = malloc (sizeof *callfree);
+ if (callfree == NULL)
+ rtems_panic ("No memory for timeout table entry");
+ callfree->c_next = NULL;
+ }
+
+ new = callfree;
+ callfree = new->c_next;
+ new->c_arg = arg;
+ new->c_func = ftn;
+
+ /*
+ * The time for each event is stored as a difference from the time
+ * of the previous event on the queue. Walk the queue, correcting
+ * the ticks argument for queue entries passed. Correct the ticks
+ * value for the queue entry immediately after the insertion point
+ * as well. Watch out for negative c_time values; these represent
+ * overdue events.
+ */
+ for (p = &calltodo;
+ (t = p->c_next) != NULL && ticks > t->c_time; p = t)
+ if (t->c_time > 0)
+ ticks -= t->c_time;
+ new->c_time = ticks;
+ if (t != NULL)
+ t->c_time -= ticks;
+
+ /* Insert the new entry into the queue. */
+ p->c_next = new;
+ new->c_next = t;
+}
+
+/*
+ * Ticks till specified time
+ * XXX: This version worries only about seconds, but that's good
+ * enough for the way the network code uses this routine.
+ */
+int
+hzto(struct timeval *tv)
+{
+ long diff = tv->tv_sec - rtems_bsdnet_seconds_since_boot();
+
+ if (diff <= 0)
+ return 1;
+ return diff * rtems_bsdnet_ticks_per_second;
+}
+
+/*
+ * Kernel debugging
+ */
+int rtems_bsdnet_log_priority;
+void
+rtems_bsdnet_log (int priority, const char *fmt, ...)
+{
+ va_list args;
+
+ if (priority & rtems_bsdnet_log_priority) {
+ va_start (args, fmt);
+ vprintf (fmt, args);
+ va_end (args);
+ }
+}
+
+/*
+ * IP header checksum routine for processors which don't have an inline version
+ */
+
+struct ip;
+
+u_int in_cksum_hdr(const struct ip *);
+
+u_int
+in_cksum_hdr (const struct ip *ip)
+{
+ uint32_t sum;
+ const uint16_t *sp;
+ int i;
+
+ sum = 0;
+ sp = (uint16_t *)ip;
+ for (i = 0 ; i < 10 ; i++)
+ sum += *sp++;
+ while (sum > 0xFFFF)
+ sum = (sum & 0xffff) + (sum >> 16);
+ return ~sum & 0xFFFF;
+}
+
+/*
+ * Manipulate routing tables
+ */
+int rtems_bsdnet_rtrequest (
+ int req,
+ struct sockaddr *dst,
+ struct sockaddr *gateway,
+ struct sockaddr *netmask,
+ int flags,
+ struct rtentry **net_nrt)
+{
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ error = rtrequest (req, dst, gateway, netmask, flags, net_nrt);
+ rtems_bsdnet_semaphore_release ();
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+static bool
+rtems_bsdnet_setup_interface(
+ const char *name,
+ const char *ip_address,
+ const char *ip_netmask
+)
+{
+ struct sockaddr_in address;
+ struct sockaddr_in netmask;
+ short flags;
+
+ /*
+ * Bring interface up
+ */
+ flags = IFF_UP;
+ if (rtems_bsdnet_ifconfig (name, SIOCSIFFLAGS, &flags) < 0) {
+ printf ("Can't bring %s up: %s\n", name, strerror (errno));
+ return false;
+ }
+
+ /*
+ * Set interface netmask
+ */
+ rtems_bsdnet_initialize_sockaddr_in(&netmask);
+ netmask.sin_addr.s_addr = inet_addr (ip_netmask);
+ if (rtems_bsdnet_ifconfig (name, SIOCSIFNETMASK, &netmask) < 0) {
+ printf ("Can't set %s netmask: %s\n", name, strerror (errno));
+ return false;
+ }
+
+ /*
+ * Set interface address
+ */
+ rtems_bsdnet_initialize_sockaddr_in(&address);
+ address.sin_addr.s_addr = inet_addr (ip_address);
+ if (rtems_bsdnet_ifconfig (name, SIOCSIFADDR, &address) < 0) {
+ printf ("Can't set %s address: %s\n", name, strerror (errno));
+ return false;
+ }
+
+ /*
+ * Set interface broadcast address if the interface has the
+ * broadcast flag set.
+ */
+ if (rtems_bsdnet_ifconfig (name, SIOCGIFFLAGS, &flags) < 0) {
+ printf ("Can't read %s flags: %s\n", name, strerror (errno));
+ return false;
+ }
+
+ if (flags & IFF_BROADCAST) {
+ struct sockaddr_in broadcast;
+
+ rtems_bsdnet_initialize_sockaddr_in(&broadcast);
+ broadcast.sin_addr.s_addr =
+ address.sin_addr.s_addr | ~netmask.sin_addr.s_addr;
+ if (rtems_bsdnet_ifconfig (name, SIOCSIFBRDADDR, &broadcast) < 0) {
+ struct in_addr in_addr;
+ char buf[20];
+ in_addr.s_addr = broadcast.sin_addr.s_addr;
+ if (!inet_ntop(AF_INET, &in_addr, buf, sizeof(buf)))
+ strcpy(buf,"?.?.?.?");
+ printf ("Can't set %s broadcast address %s: %s\n",
+ name, buf, strerror (errno));
+ }
+ }
+
+ return true;
+}
+
+static int
+rtems_bsdnet_setup (void)
+{
+ struct rtems_bsdnet_ifconfig *ifp;
+ int i;
+ bool any_if_configured = false;
+
+ /*
+ * Set local parameters
+ */
+ if (rtems_bsdnet_config.hostname)
+ sethostname (rtems_bsdnet_config.hostname,
+ strlen (rtems_bsdnet_config.hostname));
+ if (rtems_bsdnet_config.domainname)
+ rtems_bsdnet_domain_name =
+ strdup (rtems_bsdnet_config.domainname);
+ if (rtems_bsdnet_config.log_host)
+ rtems_bsdnet_log_host_address.s_addr =
+ inet_addr (rtems_bsdnet_config.log_host);
+ for (i = 0 ; i < sizeof rtems_bsdnet_config.name_server /
+ sizeof rtems_bsdnet_config.name_server[0] ; i++) {
+ if (!rtems_bsdnet_config.name_server[i])
+ break;
+ rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count++].s_addr
+ = inet_addr (rtems_bsdnet_config.name_server[i]);
+ }
+ for (i = 0 ; i < sizeof rtems_bsdnet_config.ntp_server /
+ sizeof rtems_bsdnet_config.ntp_server[0] ; i++) {
+ if (!rtems_bsdnet_config.ntp_server[i])
+ break;
+ rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count++].s_addr
+ = inet_addr (rtems_bsdnet_config.ntp_server[i]);
+ }
+
+ /*
+ * Configure interfaces
+ */
+ any_if_configured |= rtems_bsdnet_setup_interface(
+ "lo0",
+ "127.0.0.1",
+ "255.0.0.0"
+ );
+ for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) {
+ if (ifp->ip_address == NULL)
+ continue;
+
+ any_if_configured |= rtems_bsdnet_setup_interface(
+ ifp->name,
+ ifp->ip_address,
+ ifp->ip_netmask
+ );
+ }
+
+ /*
+ * Set default route
+ */
+ if (rtems_bsdnet_config.gateway && any_if_configured) {
+ struct sockaddr_in address;
+ struct sockaddr_in netmask;
+ struct sockaddr_in gateway;
+
+ rtems_bsdnet_initialize_sockaddr_in(&address);
+ rtems_bsdnet_initialize_sockaddr_in(&netmask);
+ rtems_bsdnet_initialize_sockaddr_in(&gateway);
+
+ gateway.sin_addr.s_addr = inet_addr (rtems_bsdnet_config.gateway);
+
+ if (rtems_bsdnet_rtrequest (
+ RTM_ADD,
+ (struct sockaddr *)&address,
+ (struct sockaddr *)&gateway,
+ (struct sockaddr *)&netmask,
+ (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0) {
+ printf ("Can't set default route: %s\n", strerror (errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Initialize the network
+ */
+int
+rtems_bsdnet_initialize_network(void)
+{
+ struct rtems_bsdnet_ifconfig *ifp;
+
+ /*
+ * Start network tasks.
+ * Initialize BSD network data structures.
+ */
+ if (rtems_bsdnet_initialize () < 0)
+ return -1;
+
+ /*
+ * Attach interfaces
+ */
+ for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) {
+ rtems_bsdnet_attach (ifp);
+ }
+
+ /*
+ * Bring up the network
+ */
+ if (rtems_bsdnet_setup () < 0)
+ return -1;
+ if (rtems_bsdnet_config.bootp)
+ (*rtems_bsdnet_config.bootp)();
+ return 0;
+}
+
+/*
+ * Attach a network interface.
+ */
+void rtems_bsdnet_attach(struct rtems_bsdnet_ifconfig *ifp)
+{
+ if (ifp) {
+ rtems_bsdnet_semaphore_obtain ();
+ (ifp->attach)(ifp, 1);
+ rtems_bsdnet_semaphore_release ();
+ }
+}
+
+/*
+ * Detach a network interface.
+ */
+void rtems_bsdnet_detach (struct rtems_bsdnet_ifconfig *ifp)
+{
+ if (ifp) {
+ rtems_bsdnet_semaphore_obtain ();
+ (ifp->attach)(ifp, 0);
+ rtems_bsdnet_semaphore_release ();
+ }
+}
+
+/*
+ * Interface Configuration.
+ */
+int rtems_bsdnet_ifconfig(const char *ifname, uint32_t cmd, void *param)
+{
+ int s, r = 0;
+ struct ifreq ifreq;
+
+ /*
+ * Configure interfaces
+ */
+ s = socket (AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return -1;
+
+ strncpy (ifreq.ifr_name, ifname, IFNAMSIZ);
+
+ rtems_bsdnet_semaphore_obtain ();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ case SIOCSIFNETMASK:
+ memcpy (&ifreq.ifr_addr, param, sizeof (struct sockaddr));
+ r = ioctl (s, cmd, &ifreq);
+ break;
+
+ case OSIOCGIFADDR:
+ case SIOCGIFADDR:
+ case OSIOCGIFNETMASK:
+ case SIOCGIFNETMASK:
+ if ((r = ioctl (s, cmd, &ifreq)) < 0)
+ break;
+ memcpy (param, &ifreq.ifr_addr, sizeof (struct sockaddr));
+ break;
+
+ case SIOCGIFFLAGS:
+ case SIOCSIFFLAGS:
+ if ((r = ioctl (s, SIOCGIFFLAGS, &ifreq)) < 0)
+ break;
+ if (cmd == SIOCGIFFLAGS) {
+ *((short*) param) = ifreq.ifr_flags;
+ break;
+ }
+ ifreq.ifr_flags |= *((short*) param);
+ if ( (*((short*) param) & IFF_UP ) == 0 ) {
+ /* set the interface down */
+ ifreq.ifr_flags &= ~(IFF_UP);
+ }
+ r = ioctl (s, SIOCSIFFLAGS, &ifreq);
+ break;
+
+ case SIOCSIFDSTADDR:
+ memcpy (&ifreq.ifr_dstaddr, param, sizeof (struct sockaddr));
+ r = ioctl (s, cmd, &ifreq);
+ break;
+
+ case OSIOCGIFDSTADDR:
+ case SIOCGIFDSTADDR:
+ if ((r = ioctl (s, cmd, &ifreq)) < 0)
+ break;
+ memcpy (param, &ifreq.ifr_dstaddr, sizeof (struct sockaddr));
+ break;
+
+ case SIOCSIFBRDADDR:
+ memcpy (&ifreq.ifr_broadaddr, param, sizeof (struct sockaddr));
+ r = ioctl (s, cmd, &ifreq);
+ break;
+
+ case OSIOCGIFBRDADDR:
+ case SIOCGIFBRDADDR:
+ if ((r = ioctl (s, cmd, &ifreq)) < 0)
+ break;
+ memcpy (param, &ifreq.ifr_broadaddr, sizeof (struct sockaddr));
+ break;
+
+ case SIOCSIFMETRIC:
+ ifreq.ifr_metric = *((int*) param);
+ r = ioctl (s, cmd, &ifreq);
+ break;
+
+ case SIOCGIFMETRIC:
+ if ((r = ioctl (s, cmd, &ifreq)) < 0)
+ break;
+ *((int*) param) = ifreq.ifr_metric;
+ break;
+
+ case SIOCSIFMTU:
+ ifreq.ifr_mtu = *((int*) param);
+ r = ioctl (s, cmd, &ifreq);
+ break;
+
+ case SIOCGIFMTU:
+ if ((r = ioctl (s, cmd, &ifreq)) < 0)
+ break;
+ *((int*) param) = ifreq.ifr_mtu;
+ break;
+
+ case SIOCSIFPHYS:
+ ifreq.ifr_phys = *((int*) param);
+ r = ioctl (s, cmd, &ifreq);
+ break;
+
+ case SIOCGIFPHYS:
+ if ((r = ioctl (s, cmd, &ifreq)) < 0)
+ break;
+ *((int*) param) = ifreq.ifr_phys;
+ break;
+
+ case SIOCSIFMEDIA:
+ ifreq.ifr_media = *((int*) param);
+ r = ioctl (s, cmd, &ifreq);
+ break;
+
+ case SIOCGIFMEDIA:
+ /* 'param' passes the phy index they want to
+ * look at...
+ */
+ ifreq.ifr_media = *((int*) param);
+ if ((r = ioctl (s, cmd, &ifreq)) < 0)
+ break;
+ *((int*) param) = ifreq.ifr_media;
+ break;
+
+ case SIOCAIFADDR:
+ case SIOCDIFADDR:
+ r = ioctl(s, cmd, (struct ifreq *) param);
+ break;
+
+ default:
+ errno = EOPNOTSUPP;
+ r = -1;
+ break;
+ }
+
+ rtems_bsdnet_semaphore_release ();
+
+ close (s);
+ return r;
+}
+
+/**
+ * @brief Splits a network interface name with interface configuration @a
+ * config into the unit name and number parts.
+ *
+ * Memory for the unit name will be allocated from the heap and copied to @a
+ * namep. If @a namep is NULL nothing will be allocated and copied.
+ *
+ * Returns the unit number or -1 on error.
+ */
+int
+rtems_bsdnet_parse_driver_name (const struct rtems_bsdnet_ifconfig *config, char **namep)
+{
+ const char *cp = config->name;
+ char c;
+ int unitNumber = 0;
+
+ if (cp == NULL) {
+ printf ("No network driver name.\n");
+ return -1;
+ }
+ while ((c = *cp++) != '\0') {
+ if ((c >= '0') && (c <= '9')) {
+ int len = cp - config->name;
+ if ((len < 2) || (len > 50))
+ break;
+ for (;;) {
+ unitNumber = (unitNumber * 10) + (c - '0');
+ c = *cp++;
+ if (c == '\0') {
+ if (namep != NULL) {
+ char *unitName = malloc (len);
+ if (unitName == NULL) {
+ printf ("No memory.\n");
+ return -1;
+ }
+ strncpy (unitName, config->name, len - 1);
+ unitName[len-1] = '\0';
+ *namep = unitName;
+ }
+ return unitNumber;
+ }
+ if ((c < '0') || (c > '9'))
+ break;
+ }
+ break;
+ }
+ }
+ printf ("Bad network driver name `%s'.\n", config->name);
+ return -1;
+}
+
+/*
+ * Handle requests for more network memory
+ * XXX: Another possibility would be to use a semaphore here with
+ * a release in the mbuf free macro. I have chosen this `polling'
+ * approach because:
+ * 1) It is simpler.
+ * 2) It adds no complexity to the free macro.
+ * 3) Running out of mbufs should be a rare
+ * condition -- predeployment testing of
+ * an application should indicate the
+ * required mbuf pool size.
+ * XXX: Should there be a panic if a task is stuck in the loop for
+ * more than a minute or so?
+ */
+int
+m_mballoc(int nmb, int nowait)
+{
+ if (nowait)
+ return 0;
+ m_reclaim ();
+ if (mmbfree == NULL) {
+ int try = 0;
+ int print_limit = 30 * rtems_bsdnet_ticks_per_second;
+
+ mbstat.m_wait++;
+ for (;;) {
+ uint32_t nest_count = rtems_bsdnet_semaphore_release_recursive ();
+ rtems_task_wake_after (1);
+ rtems_bsdnet_semaphore_obtain_recursive (nest_count);
+ if (mmbfree)
+ break;
+ if (++try >= print_limit) {
+ printf ("Still waiting for mbuf.\n");
+ try = 0;
+ }
+ }
+ }
+ else {
+ mbstat.m_drops++;
+ }
+ return 1;
+}
+
+int
+m_clalloc(int ncl, int nowait)
+{
+ if (nowait)
+ return 0;
+ m_reclaim ();
+ if (mclfree == NULL) {
+ int try = 0;
+ int print_limit = 30 * rtems_bsdnet_ticks_per_second;
+
+ mbstat.m_wait++;
+ for (;;) {
+ uint32_t nest_count = rtems_bsdnet_semaphore_release_recursive ();
+ rtems_task_wake_after (1);
+ rtems_bsdnet_semaphore_obtain_recursive (nest_count);
+ if (mclfree)
+ break;
+ if (++try >= print_limit) {
+ printf ("Still waiting for mbuf cluster.\n");
+ try = 0;
+ }
+ }
+ }
+ else {
+ mbstat.m_drops++;
+ }
+ return 1;
+}
+
diff --git a/rtems/rtems_malloc_mbuf.c b/rtems/rtems_malloc_mbuf.c
new file mode 100644
index 0000000..a12e329
--- /dev/null
+++ b/rtems/rtems_malloc_mbuf.c
@@ -0,0 +1,33 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define RTEMS_FAST_MUTEX
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * We want to use the REAL system malloc. Do not let the BSD malloc macro
+ * invade this file.
+ */
+extern void *malloc(size_t);
+
+/*
+ * Default allocator for mbuf data. Over-ride in user code to change
+ * the way mbuf's are allocated.
+ */
+
+void* rtems_bsdnet_malloc_mbuf(size_t size, int type)
+{
+ return malloc(size);
+}
+
+
diff --git a/rtems/rtems_mii_ioctl.c b/rtems/rtems_mii_ioctl.c
new file mode 100644
index 0000000..2559f4b
--- /dev/null
+++ b/rtems/rtems_mii_ioctl.c
@@ -0,0 +1,172 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
+ * to be used by ethernet drivers [from their ioctl].
+ *
+ * USERSPACE UTILITIES
+ *
+ * NOTE: This much simpler than the BSD ifmedia API
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2005,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <rtems.h>
+#include <inttypes.h>
+
+#undef _KERNEL
+
+#include <rtems/rtems_mii_ioctl.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+static struct ifmedia_description shared_media_strings[] =
+ IFM_SUBTYPE_SHARED_DESCRIPTIONS;
+static struct ifmedia_description ethern_media_strings[] =
+ IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
+static struct ifmedia_description eth_al_media_strings[] =
+ IFM_SUBTYPE_ETHERNET_ALIASES;
+
+static const char *
+find_desc (int tag, struct ifmedia_description *list)
+{
+ while (list->ifmt_string && tag != list->ifmt_word)
+ list++;
+ return list->ifmt_string;
+}
+
+#define WHATPRINT(buf,sz,fmt...) \
+ ( (sz) > 0 ? snprintf((buf),(sz),fmt) : fprintf((buf) ? (FILE*)(buf) : stdout, fmt) )
+
+int
+rtems_ifmedia2str (int media, char *buf, int bufsz)
+{
+ const char *mdesc;
+ const char *dupdesc = 0;
+
+ /* only ethernet supported, so far */
+ if (IFM_ETHER != IFM_TYPE (media))
+ return -1;
+
+ if (!(mdesc = find_desc (IFM_SUBTYPE (media), shared_media_strings)))
+ mdesc = find_desc (IFM_SUBTYPE (media), ethern_media_strings);
+
+ if (!mdesc)
+ return -1;
+
+ if (IFM_NONE != IFM_SUBTYPE (media))
+ dupdesc = IFM_FDX & media ? " full-duplex" : " half-duplex";
+
+ return WHATPRINT (buf, bufsz,
+ "Ethernet [phy instance: %" PRId32 "]: (link %s, autoneg %s) -- media: %s%s",
+ (int32_t) IFM_INST (media),
+ IFM_LINK_OK & media ? "ok" : "down",
+ IFM_ANEG_DIS & media ? "off" : "on",
+ mdesc, dupdesc ? dupdesc : "");
+}
+
+static int
+find_tag (const char *desc, struct ifmedia_description *list)
+{
+ while (list->ifmt_string) {
+ if (strstr (desc, list->ifmt_string))
+ return list->ifmt_word;
+ list++;
+ }
+ return -1;
+}
+
+
+/* convert a string to a media word
+ * RETURNS: 0 on failure; valid results have always at least IFM_ETHER set
+ */
+int
+rtems_str2ifmedia (const char *str, int phy)
+{
+ int sub, opt = 0;
+ char *chpt;
+
+ if (!strncmp (str, "auto", 4)) {
+ sub = IFM_AUTO;
+ } else if ((sub = find_tag (str, ethern_media_strings)) < 0) {
+ if ((sub = find_tag (str, eth_al_media_strings)) < 0) {
+ /* allow more */
+
+ /* if no number, 0 is returned which will not pass the test */
+ switch (strtol (str, &chpt, 10)) {
+ case 10:
+ sub = IFM_10_T;
+ break;
+ case 100:
+ sub = IFM_100_TX;
+ break;
+ case 1000:
+ sub = IFM_1000_T;
+ break;
+ default:
+ return 0;
+ }
+
+ /* need 'b' or 'base' */
+ if ('b' != *chpt++)
+ return 0;
+ if (!strncmp (chpt, "ase", 3))
+ chpt += 3;
+ if (toupper ((unsigned char)*chpt++) != 'T')
+ return 0;
+ if (IFM_100_TX == sub && toupper ((unsigned char)*chpt++) != 'X')
+ return 0;
+ }
+ }
+
+ if (strstr (str, "full") || strstr (str, "FDX") || strstr (str, "fdx"))
+ opt |= IFM_FDX;
+
+ return IFM_MAKEWORD (IFM_ETHER, sub, opt, phy);
+}
diff --git a/rtems/rtems_mii_ioctl.h b/rtems/rtems_mii_ioctl.h
new file mode 100644
index 0000000..dfeebf1
--- /dev/null
+++ b/rtems/rtems_mii_ioctl.h
@@ -0,0 +1,139 @@
+/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
+ * to be used by ethernet drivers [from their ioctl].
+ *
+ * NOTE: This much simpler than the BSD ifmedia API
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2005,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+#ifndef RTEMS_MII_IOCTL_H
+#define RTEMS_MII_IOCTL_H
+
+#include <dev/mii/mii.h> /* MII register definitions */
+#include <net/if_media.h> /* media word definitions; rest of API (ifmedia) unused! */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL) || defined(KERNEL) || \
+ defined(__KERNEL) || defined(__KERNEL__)
+/* mdio routines to be provided by driver */
+
+/* read mii register 'reg' at 'phy' (-1 meaning any/currently active)
+ * RETURNS 0 on success, -1 otherwise (e.g., illegal phy)
+ */
+typedef int (*rtems_mdio_read_func) (int phy, void *uarg, unsigned reg,
+ uint32_t * pval);
+
+/* write mii register 'reg' at 'phy' (-1 meaning any/currently active)
+ * RETURNS 0 on success, -1 otherwise (e.g., illegal phy)
+ */
+typedef int (*rtems_mdio_write_func) (int phy, void *uarg, unsigned reg,
+ uint32_t val);
+
+/* Values to this must be provided by the driver */
+struct rtems_mdio_info {
+ rtems_mdio_read_func mdio_r;
+ rtems_mdio_write_func mdio_w;
+ unsigned has_gmii:1; /* supports gigabit */
+};
+
+/* Implement SIOCSIFMEDIA/SIOCGIFMEDIA; get/set the current media word. Note
+ * that this does NOT implement the full BSD 'ifmedia' API; also, it only
+ * implements IFM_ETHER...
+ *
+ * INPUT:
+ * SIOCGIFMEDIA: the media word must set the phy instance (-1 for 'any')
+ *
+ */
+int
+rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, uint32_t cmd,
+ int *media);
+
+#endif
+
+/* The driver flags have the following meaning (SIOCGIFMEDIA only):
+ */
+#define IFM_LINK_OK IFM_FLAG0
+#define IFM_ANEG_DIS IFM_FLAG1 /* autoneg. disabled; media forced */
+
+/* convert a media word to a string;
+ *
+ * RETURNS: number of characters written to 'buf'
+ *
+ * INPUT: if 'bufsz' is set to IFMEDIA2STR_PRINT_TO_FILE, 'buf' can be a FILE
+ * pointer where the info is printed insted. This can be NULL in which
+ * case 'stdout' is used.
+ */
+
+#define IFMEDIA2STR_PRINT_TO_FILE 0
+
+int rtems_ifmedia2str (int media, char *buf, int bufsz);
+
+/* convert a string to a media word
+ * RETURNS: 0 on failure (unrecognized or invalid mode);
+ * valid results have always at least IFM_ETHER set.
+ *
+ * In addition to IFM_SUBTYPE_ETHERNET_DESCRIPTIONS and
+ * IFM_SUBTYPE_ETHERNET_ALIASES, the strings
+ *
+ * '10' [ '0' [ '0' ]] 'b' [ 'ase' ] ( 't' | 'T' )
+ * (* if 100bT [ 'x' | 'X' ] is required here *)
+ *
+ * are recognized (e.g., 10bT, 100bTX)
+ *
+ * if any of the strings 'full' or 'FDX' or 'fdx' is present, a full-duplex mode
+ * is selected (half-duplex otherwise).
+ * e.g., '100bTx-full'
+ */
+
+int rtems_str2ifmedia (const char *str, int phy);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/rtems/rtems_mii_ioctl_kern.c b/rtems/rtems_mii_ioctl_kern.c
new file mode 100644
index 0000000..2944f0a
--- /dev/null
+++ b/rtems/rtems_mii_ioctl_kern.c
@@ -0,0 +1,260 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
+ * to be used by ethernet drivers [from their ioctl].
+ *
+ * KERNEL PART (support for drivers)
+ *
+ * NOTE: This much simpler than the BSD ifmedia API
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2005,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+/* include first to avoid 'malloc' clash with rtems_bsdnet_malloc() hack */
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <rtems/rtems_mii_ioctl.h>
+
+#include <errno.h>
+
+
+#define DEBUG
+
+
+#ifndef MII_1000TCR
+#define MII_1000TCR MII_100T2CR
+#endif
+
+#ifndef MII_1000TSR
+#define MII_1000TSR MII_100T2SR
+#endif
+
+int
+rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, uint32_t cmd,
+ int *media)
+{
+ uint32_t bmcr, bmsr, aner, bmcr2 = 0, bmsr2 = 0, anar, lpar;
+ int phy = IFM_INST (*media);
+ uint32_t tmp;
+ int subtype = 0, options = 0;
+
+ switch (cmd) {
+ default:
+ return EINVAL;
+
+#ifdef DEBUG
+ case 0:
+#endif
+ case SIOCGIFMEDIA:
+ if (info->mdio_r (phy, uarg, MII_BMCR, &bmcr))
+ return EINVAL;
+ /* read BMSR twice to clear latched link status low */
+ if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
+ return EINVAL;
+ if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
+ return EINVAL;
+ if (info->mdio_r (phy, uarg, MII_ANER, &aner))
+ return EINVAL;
+ if (info->has_gmii) {
+ if (info->mdio_r (phy, uarg, MII_1000TCR, &bmcr2))
+ return EINVAL;
+ if (info->mdio_r (phy, uarg, MII_1000TSR, &bmsr2))
+ return EINVAL;
+ }
+
+ /* link status */
+ if (BMSR_LINK & bmsr)
+ options |= IFM_LINK_OK;
+
+ /* do we have autonegotiation disabled ? */
+ if (!(BMCR_AUTOEN & bmcr)) {
+ options |= IFM_ANEG_DIS;
+
+ /* duplex is enforced */
+ options |= BMCR_FDX & bmcr ? IFM_FDX : IFM_HDX;
+
+ /* determine speed */
+ switch (BMCR_SPEED (bmcr)) {
+ case BMCR_S10:
+ subtype = IFM_10_T;
+ break;
+ case BMCR_S100:
+ subtype = IFM_100_TX;
+ break;
+ case BMCR_S1000:
+ subtype = IFM_1000_T;
+ break;
+ default:
+ return ENOTSUP; /* ?? */
+ }
+ } else if (!(BMSR_LINK & bmsr) || !(BMSR_ACOMP & bmsr)) {
+ subtype = IFM_NONE;
+ } else {
+ /* everything ok on our side */
+
+ if ( ! (ANER_LPAN & aner) ) {
+ /* Link partner doesn't autonegotiate --> our settings are the
+ * result of 'parallel detect' (in particular: duplex status is HALF
+ * according to the standard!).
+ * Let them know that something's fishy...
+ */
+ options |= IFM_ANEG_DIS;
+ }
+
+ tmp = ((bmcr2 << 2) & bmsr2) & (GTSR_LP_1000THDX | GTSR_LP_1000TFDX);
+ if (tmp) {
+ if (GTSR_LP_1000TFDX & tmp)
+ options |= IFM_FDX;
+ subtype = IFM_1000_T;
+ } else {
+ if (info->mdio_r (phy, uarg, MII_ANAR, &anar))
+ return EINVAL;
+ if (info->mdio_r (phy, uarg, MII_ANLPAR, &lpar))
+ return EINVAL;
+ if (ANLPAR_ACK & lpar) {
+ /* this is a negotiated link; otherwise we merely detect the partner's ability */
+ }
+ tmp = anar & lpar;
+ if (ANLPAR_TX_FD & tmp) {
+ options |= IFM_FDX;
+ subtype = IFM_100_TX;
+ } else if (ANLPAR_T4 & tmp) {
+ subtype = IFM_100_T4;
+ } else if (ANLPAR_TX & tmp) {
+ subtype = IFM_100_TX;
+ } else if (ANLPAR_10_FD & tmp) {
+ options |= IFM_FDX;
+ subtype = IFM_10_T;
+ } else {
+ subtype = IFM_10_T;
+ }
+ }
+ }
+
+ *media = IFM_MAKEWORD (IFM_ETHER, subtype, options, phy);
+
+ break;
+
+#ifdef DEBUG
+ case 1:
+#endif
+ case SIOCSIFMEDIA:
+ if (IFM_ETHER != IFM_TYPE (*media))
+ return EINVAL;
+
+ if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
+ return EINVAL;
+
+ tmp = (IFM_FDX & *media);
+
+ switch (IFM_SUBTYPE (*media)) {
+ default:
+ return ENOTSUP;
+
+ case IFM_AUTO:
+ bmcr = BMCR_AUTOEN | BMCR_STARTNEG;
+ tmp = 0;
+ break;
+
+ case IFM_1000_T:
+ if (!info->has_gmii)
+ return ENOTSUP;
+
+ if (info->mdio_r (phy, uarg, MII_EXTSR, &bmsr2))
+ return EINVAL;
+
+ if (!(bmsr2 & (tmp ? EXTSR_1000TFDX : EXTSR_1000THDX)))
+ return EOPNOTSUPP;
+
+ /* NOTE: gige standard demands auto-negotiation for gige links.
+ * Disabling autoneg did NOT work on the PHYs I tried
+ * (BCM5421S, intel 82540).
+ * I've seen drivers that simply change what they advertise
+ * to the desired gig mode and re-negotiate.
+ * We could do that here, too, but we don't see the point -
+ * If autoneg works fine then we can as well use it.
+ */
+ bmcr = BMCR_S1000;
+ break;
+
+ case IFM_100_TX:
+ if (!(bmsr & (tmp ? BMSR_100TXFDX : BMSR_100TXHDX)))
+ return EOPNOTSUPP;
+ bmcr = BMCR_S100;
+ break;
+
+ case IFM_10_T:
+ if (!(bmsr & (tmp ? BMSR_10TFDX : BMSR_10THDX)))
+ return EOPNOTSUPP;
+ bmcr = BMCR_S10;
+ break;
+ }
+
+ if (tmp)
+ bmcr |= BMCR_FDX;
+
+ if (info->mdio_w (phy, uarg, MII_BMCR, bmcr))
+ return EINVAL;
+
+ /* TODO: should we adapt advertised capabilites ? */
+
+ break;
+ }
+
+ return 0;
+}
diff --git a/rtems/rtems_netdb.h b/rtems/rtems_netdb.h
new file mode 100644
index 0000000..ca4d3dd
--- /dev/null
+++ b/rtems/rtems_netdb.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef _RTEMS_RTEMS_NETDB_H
+#define _RTEMS_RTEMS_NETDB_H
+
+#include <netdb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* DO NOT USE THESE, THEY ARE SUBJECT TO CHANGE AND ARE NOT PORTABLE!!! */
+void _sethosthtent(int);
+void _endhosthtent(void);
+void _sethostdnsent(int);
+void _endhostdnsent(void);
+void _setnethtent(int);
+void _endnethtent(void);
+void _setnetdnsent(int);
+void _endnetdnsent(void);
+struct hostent * _gethostbyhtname(const char *, int);
+struct hostent * _gethostbydnsname(const char *, int);
+struct hostent * _gethostbynisname(const char *, int);
+struct hostent * _gethostbyhtaddr (const char *, int, int);
+struct hostent * _gethostbydnsaddr(const char *, int, int);
+struct hostent * _gethostbynisaddr(const char *, int, int);
+struct netent * _getnetbyhtname (const char *);
+struct netent * _getnetbydnsname(const char *);
+struct netent * _getnetbynisname(const char *);
+struct netent * _getnetbyhtaddr (unsigned long, int);
+struct netent * _getnetbydnsaddr(unsigned long, int);
+struct netent * _getnetbynisaddr(unsigned long, int);
+void _map_v4v6_address(const char *, char *);
+void _map_v4v6_hostent(struct hostent *, char **, int *len);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_RTEMS_NETDB_H */
diff --git a/rtems/rtems_netinet_in.h b/rtems/rtems_netinet_in.h
new file mode 100644
index 0000000..53240e4
--- /dev/null
+++ b/rtems/rtems_netinet_in.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RTEMS_RTEMS_NETINET_IN_H
+#define _RTEMS_RTEMS_NETINET_IN_H
+
+#include <rtems.h>
+#include <netinet/in.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * Ports > IPPORT_USERRESERVED are reserved
+ * for servers, not necessarily privileged. (IP_PORTRANGE_DEFAULT)
+ */
+#define IPPORT_USERRESERVED 5000
+
+/* Deprecated in current FreeBSD */
+#define IPCTL_RTEXPIRE 5 /* cloned route expiration time */
+#define IPCTL_RTMINEXPIRE 6 /* min value for expiration time */
+#define IPCTL_RTMAXCACHE 7 /* trigger level for dynamic expire */
+
+int in_cksum(struct mbuf *, int);
+
+/* Firewall hooks */
+struct ip;
+typedef int ip_fw_chk_t(struct ip**, int, struct ifnet*, int, struct mbuf**);
+typedef int ip_fw_ctl_t(int, struct mbuf**);
+extern ip_fw_chk_t *ip_fw_chk_ptr;
+extern ip_fw_ctl_t *ip_fw_ctl_ptr;
+
+/* IP NAT hooks */
+typedef int ip_nat_t(struct ip**, struct mbuf**, struct ifnet*, int);
+typedef int ip_nat_ctl_t(int, struct mbuf**);
+extern ip_nat_t *ip_nat_ptr;
+extern ip_nat_ctl_t *ip_nat_ctl_ptr;
+#define IP_NAT_IN 0x00000001
+#define IP_NAT_OUT 0x00000002
+
+/*
+ * Options for use with [gs]etsockopt at the IP level.
+ *
+ * The value is stored in an integer. Use negative numbers to avoid conflicts
+ * with BSD.
+ */
+#define IP_NAT (-55) /* set/get NAT opts */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_RTEMS_NETINET_IN_H */
diff --git a/rtems/rtems_select.c b/rtems/rtems_select.c
new file mode 100644
index 0000000..0b58b6a
--- /dev/null
+++ b/rtems/rtems_select.c
@@ -0,0 +1,179 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+/* #include <stdlib.h> */
+#include <stdio.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/proc.h>
+#include <sys/filio.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+/*
+ *********************************************************************
+ * RTEMS implementation of select() system call *
+ *********************************************************************
+ */
+
+/*
+ * This implementation is quite restricted:
+ * Works on sockets only -- no support for other devices!
+ * A given socket can be in a read-select or a read/recv* by only
+ * one task at a time.
+ * A given socket can be in a write-select or a write/send* by only
+ * one task at a time.
+ *
+ * NOTE - select() is a very expensive system call. It should be avoided
+ * if at all possible. In many cases, rewriting the application
+ * to use multiple tasks (one per socket) is a better solution.
+ */
+
+static __inline int imin(int a, int b) { return (a < b ? a : b); }
+struct socket *rtems_bsdnet_fdToSocket(int fd);
+
+static int
+socket_select (struct socket *so, int which, rtems_id tid)
+{
+ switch (which) {
+
+ case FREAD:
+ if (soreadable(so))
+ return (1);
+ so->so_rcv.sb_flags |= SB_WAIT;
+ so->so_rcv.sb_sel.si_pid = tid;
+ break;
+
+ case FWRITE:
+ if (sowriteable(so))
+ return (1);
+ so->so_snd.sb_flags |= SB_WAIT;
+ so->so_snd.sb_sel.si_pid = tid;
+ break;
+
+ case 0:
+ if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
+ return (1);
+ so->so_rcv.sb_sel.si_pid = tid;
+ break;
+ }
+ return (0);
+}
+
+static int
+selscan (rtems_id tid, fd_mask **ibits, fd_mask **obits, int nfd, int *retval)
+{
+ struct socket *so;
+ int msk, i, fd;
+ fd_mask bits, bit;
+ int n = 0;
+ static int flag[3] = { FREAD, FWRITE, 0 };
+
+ for (msk = 0; msk < 3; msk++) {
+ if (ibits[msk] == NULL)
+ continue;
+ for (i = 0; i < nfd; i += NFDBITS) {
+ bits = ibits[msk][i/NFDBITS];
+ for (fd = i, bit = 1 ; bits && (fd < nfd) ; fd++, bit <<= 1) {
+ if ((bits & bit) == 0)
+ continue;
+ bits &= ~bit;
+ so = rtems_bsdnet_fdToSocket (fd);
+ if (so == NULL)
+ return (EBADF);
+ if (socket_select (so, flag[msk], tid)) {
+ obits[msk][fd/NFDBITS] |=
+ (1 << (fd % NFDBITS));
+ n++;
+ }
+ }
+ }
+ }
+ *retval = n;
+ return (0);
+}
+
+int
+select (int nfds, fd_set *__restrict readfds, fd_set *__restrict writefds,
+ fd_set *__restrict exceptfds, struct timeval *__restrict tv)
+{
+ fd_mask *ibits[3], *obits[3];
+ fd_set ob[3];
+ int error, timo;
+ int retval = 0;
+ rtems_id tid;
+ rtems_interval then = 0, now;
+ rtems_event_set in = SBWAIT_EVENT | RTEMS_EVENT_SYSTEM_NETWORK_CLOSE;
+ rtems_event_set out;
+
+ if (nfds < 0)
+ return (EINVAL);
+ if (tv) {
+ timo = tv->tv_sec * hz + tv->tv_usec / tick;
+ if (timo == 0)
+ timo = 1;
+ then = rtems_clock_get_ticks_since_boot();
+ }
+ else {
+ timo = 0;
+ }
+
+#define getbits(name,i) if (name) { \
+ ibits[i] = &name->fds_bits[0]; \
+ obits[i] = &ob[i].fds_bits[0]; \
+ FD_ZERO(&ob[i]); \
+ } \
+ else ibits[i] = NULL
+ getbits (readfds, 0);
+ getbits (writefds, 1);
+ getbits (exceptfds, 2);
+#undef getbits
+
+ rtems_task_ident (RTEMS_SELF, 0, &tid);
+ rtems_event_system_receive (in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &out);
+ for (;;) {
+ rtems_bsdnet_semaphore_obtain ();
+ error = selscan(tid, ibits, obits, nfds, &retval);
+ rtems_bsdnet_semaphore_release ();
+ if (error || retval)
+ break;
+ if (timo) {
+ now = rtems_clock_get_ticks_since_boot();
+ timo -= now - then;
+ if (timo <= 0)
+ break;
+ then = now;
+ }
+ rtems_event_system_receive (in, RTEMS_EVENT_ANY | RTEMS_WAIT, timo, &out);
+ }
+
+#define putbits(name,i) if (name) *name = ob[i]
+ putbits (readfds, 0);
+ putbits (writefds, 1);
+ putbits (exceptfds, 2);
+#undef putbits
+ if (error) {
+ errno = error;
+ retval = -1;
+ }
+ return (retval);
+}
diff --git a/rtems/rtems_showicmpstat.c b/rtems/rtems_showicmpstat.c
new file mode 100644
index 0000000..4862d6c
--- /dev/null
+++ b/rtems/rtems_showicmpstat.c
@@ -0,0 +1,70 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * Display ICMP statistics
+ * Don't lock the rest of the network tasks out while printing.
+ * It's no big deal if the values change while being printed.
+ */
+static void
+showicmpstat (const char *name, unsigned long n)
+{
+ if (n)
+ printf ("%35s%12lu\n", name, n);
+}
+
+/*
+ * External data we peek at during statistics reporting
+ */
+extern unsigned int icmplenPanicAvoided;
+
+void
+rtems_bsdnet_show_icmp_stats (void)
+{
+ int i;
+ char cbuf[20];
+
+ printf ("************ ICMP Statistics ************\n");
+ showicmpstat ("Calls to icmp_error()", icmpstat.icps_error);
+ showicmpstat ("Errors not sent -- old was icmp", icmpstat.icps_oldicmp);
+ for (i = 0 ; i <= ICMP_MAXTYPE ; i++) {
+ if (icmpstat.icps_outhist[i]) {
+ sprintf (cbuf, "Type %d sent", i);
+ showicmpstat (cbuf, icmpstat.icps_outhist[i]);
+ }
+ }
+ showicmpstat ("icmp_code out of range", icmpstat.icps_badcode);
+ showicmpstat ("packet < ICMP_MINLEN", icmpstat.icps_tooshort);
+ showicmpstat ("bad checksum", icmpstat.icps_checksum);
+ showicmpstat ("calculated bound mismatch", icmpstat.icps_badlen);
+ showicmpstat ("number of responses", icmpstat.icps_reflect);
+ showicmpstat ("all echo requests dropped", icmpstat.icps_allecho);
+ showicmpstat ("b/mcast echo requests dropped", icmpstat.icps_bmcastecho);
+ showicmpstat ("b/mcast tstamp requests dropped", icmpstat.icps_bmcasttstamp);
+ for (i = 0 ; i <= ICMP_MAXTYPE ; i++) {
+ if (icmpstat.icps_inhist[i]) {
+ sprintf (cbuf, "Type %d received", i);
+ showicmpstat (cbuf, icmpstat.icps_inhist[i]);
+ }
+ }
+ showicmpstat ("ICMP panic avoided", icmplenPanicAvoided);
+ printf ("\n");
+}
diff --git a/rtems/rtems_showifstat.c b/rtems/rtems_showifstat.c
new file mode 100644
index 0000000..21f21f4
--- /dev/null
+++ b/rtems/rtems_showifstat.c
@@ -0,0 +1,157 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * Display an address
+ */
+static int
+showaddress (char *name, struct sockaddr *a)
+{
+ struct sockaddr_in *sa;
+ char buf[17];
+
+ if (!a)
+ return 0;
+ printf ("%s:", name);
+ sa = (struct sockaddr_in *)a;
+ printf ("%-16s", inet_ntop (AF_INET, &sa->sin_addr, buf, sizeof(buf)));
+ return 1;
+}
+
+/*
+ * Display interface statistics
+ */
+void
+rtems_bsdnet_show_if_stats (void)
+{
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ unsigned short bit, flags;
+
+ printf ("************ INTERFACE STATISTICS ************\n");
+ for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+ printf ("***** %s%d *****\n", ifp->if_name, ifp->if_unit);
+ for (ifa = ifp->if_addrlist ; ifa ; ifa = ifa->ifa_next) {
+
+ if ( !ifa->ifa_addr )
+ continue;
+
+ switch ( ifa->ifa_addr->sa_family ) {
+ case AF_LINK:
+ {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ unsigned char *cp = (unsigned char *)LLADDR(sdl);
+ int i;
+
+ switch ( sdl->sdl_type ) {
+ case IFT_ETHER:
+ if ( (i=sdl->sdl_alen) > 0 ) {
+ printf("Ethernet Address: ");
+ do {
+ i--;
+ printf("%02X%c", *cp++, i ? ':' : '\n');
+ } while ( i>0 );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case AF_INET:
+ {
+ int printed;
+ printed = showaddress ("Address", ifa->ifa_addr);
+ if (ifp->if_flags & IFF_BROADCAST)
+ printed |= showaddress ("Broadcast Address", ifa->ifa_broadaddr);
+ if (ifp->if_flags & IFF_POINTOPOINT)
+ printed |= showaddress ("Destination Address", ifa->ifa_dstaddr);
+ printed |= showaddress ("Net mask", ifa->ifa_netmask);
+ if (printed)
+ printf ("\n");
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ printf ("Flags:");
+ for (bit = 1, flags = ifp->if_flags ; flags ; bit <<= 1) {
+ char *cp;
+ char xbuf[20];
+ switch (flags & bit) {
+ case 0: cp = NULL; break;
+ case IFF_UP: cp = "Up"; break;
+ case IFF_BROADCAST: cp = "Broadcast"; break;
+ case IFF_DEBUG: cp = "Debug"; break;
+ case IFF_LOOPBACK: cp = "Loopback"; break;
+ case IFF_POINTOPOINT: cp = "Point-to-point"; break;
+ case IFF_RUNNING: cp = "Running"; break;
+ case IFF_NOARP: cp = "No-ARP"; break;
+ case IFF_PROMISC: cp = "Promiscuous"; break;
+ case IFF_ALLMULTI: cp = "All-multicast"; break;
+ case IFF_OACTIVE: cp = "Active"; break;
+ case IFF_SIMPLEX: cp = "Simplex"; break;
+ case IFF_LINK0: cp = "Link0"; break;
+ case IFF_LINK1: cp = "Link1"; break;
+ case IFF_LINK2: cp = "Link2"; break;
+ case IFF_MULTICAST: cp = "Multicast"; break;
+ default: sprintf (xbuf, "%#x", bit); cp = xbuf; break;
+ }
+ if (cp) {
+ flags &= ~bit;
+ printf (" %s", cp);
+ }
+ }
+ printf ("\n");
+
+ printf ("Send queue limit:%-4d length:%-4d Dropped:%-8d\n",
+ ifp->if_snd.ifq_maxlen,
+ ifp->if_snd.ifq_len,
+ ifp->if_snd.ifq_drops);
+
+ /*
+ * FIXME: Could print if_data statistics here,
+ * but right now the drivers maintain their
+ * own statistics.
+ */
+
+ /*
+ * Grab the network semaphore.
+ * In most cases this is not necessary, but it's
+ * easier to always call the driver ioctl function
+ * while holding the semaphore than to try
+ * and explain why some ioctl commands are invoked
+ * while holding the semaphore and others are
+ * invoked while not holding the semaphore.
+ */
+ rtems_bsdnet_semaphore_obtain ();
+ (*ifp->if_ioctl)(ifp, SIO_RTEMS_SHOW_STATS, NULL);
+ rtems_bsdnet_semaphore_release ();
+ }
+ printf ("\n");
+}
diff --git a/rtems/rtems_showipstat.c b/rtems/rtems_showipstat.c
new file mode 100644
index 0000000..5b30da5
--- /dev/null
+++ b/rtems/rtems_showipstat.c
@@ -0,0 +1,68 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * Display IP statistics
+ * Don't lock the rest of the network tasks out while printing.
+ * It's no big deal if the values change while being printed.
+ */
+static void
+showipstat (const char *name, unsigned long n)
+{
+ if (n)
+ printf ("%35s%12lu\n", name, n);
+}
+
+void
+rtems_bsdnet_show_ip_stats (void)
+{
+ printf ("************ IP Statistics ************\n");
+ showipstat ("total packets received", ipstat.ips_total);
+ showipstat ("checksum bad", ipstat.ips_badsum);
+ showipstat ("packet too short", ipstat.ips_tooshort);
+ showipstat ("not enough data", ipstat.ips_toosmall);
+ showipstat ("ip header length < data size", ipstat.ips_badhlen);
+ showipstat ("ip length < ip header length", ipstat.ips_badlen);
+ showipstat ("fragments received", ipstat.ips_fragments);
+ showipstat ("frags dropped (dups, out of space)", ipstat.ips_fragdropped);
+ showipstat ("fragments timed out", ipstat.ips_fragtimeout);
+ showipstat ("packets forwarded", ipstat.ips_forward);
+ showipstat ("packets rcvd for unreachable dest", ipstat.ips_cantforward);
+ showipstat ("packets forwarded on same net", ipstat.ips_redirectsent);
+ showipstat ("unknown or unsupported protocol", ipstat.ips_noproto);
+ showipstat ("datagrams delivered to upper level", ipstat.ips_delivered);
+ showipstat ("total ip packets generated here", ipstat.ips_localout);
+ showipstat ("lost packets due to nobufs, etc.", ipstat.ips_odropped);
+ showipstat ("total packets reassembled ok", ipstat.ips_reassembled);
+ showipstat ("datagrams successfully fragmented", ipstat.ips_fragmented);
+ showipstat ("output fragments created", ipstat.ips_ofragments);
+ showipstat ("don't fragment flag was set, etc.", ipstat.ips_cantfrag);
+ showipstat ("error in option processing", ipstat.ips_badoptions);
+ showipstat ("packets discarded due to no route", ipstat.ips_noroute);
+ showipstat ("ip version != 4", ipstat.ips_badvers);
+ showipstat ("total raw ip packets generated", ipstat.ips_rawout);
+ showipstat ("ip length > max ip packet size", ipstat.ips_toolong);
+ showipstat ("ip input queue drops", ipintrq.ifq_drops);
+ printf ("\n");
+}
diff --git a/rtems/rtems_showmbuf.c b/rtems/rtems_showmbuf.c
new file mode 100644
index 0000000..27f8cff
--- /dev/null
+++ b/rtems/rtems_showmbuf.c
@@ -0,0 +1,69 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * Display MBUF statistics
+ * Don't lock the rest of the network tasks out while printing.
+ * It's no big deal if the values change while being printed.
+ */
+void
+rtems_bsdnet_show_mbuf_stats (void)
+{
+ int i;
+ int printed = 0;
+ char *cp;
+
+ printf ("************ MBUF STATISTICS ************\n");
+ printf ("mbufs:%4lu clusters:%4lu free:%4lu\n",
+ mbstat.m_mbufs, mbstat.m_clusters, mbstat.m_clfree);
+ printf ("drops:%4lu waits:%4lu drains:%4lu\n",
+ mbstat.m_drops, mbstat.m_wait, mbstat.m_drain);
+ for (i = 0 ; i < 20 ; i++) {
+ switch (i) {
+ case MT_FREE: cp = "free"; break;
+ case MT_DATA: cp = "data"; break;
+ case MT_HEADER: cp = "header"; break;
+ case MT_SOCKET: cp = "socket"; break;
+ case MT_PCB: cp = "pcb"; break;
+ case MT_RTABLE: cp = "rtable"; break;
+ case MT_HTABLE: cp = "htable"; break;
+ case MT_ATABLE: cp = "atable"; break;
+ case MT_SONAME: cp = "soname"; break;
+ case MT_SOOPTS: cp = "soopts"; break;
+ case MT_FTABLE: cp = "ftable"; break;
+ case MT_RIGHTS: cp = "rights"; break;
+ case MT_IFADDR: cp = "ifaddr"; break;
+ case MT_CONTROL: cp = "control"; break;
+ case MT_OOBDATA: cp = "oobdata"; break;
+ default: cp = NULL; break;
+ }
+ if ((cp != NULL) || (mbstat.m_mtypes[i] != 0)) {
+ char cbuf[16];
+ if (cp == NULL) {
+ sprintf (cbuf, "Type %d", i);
+ cp = cbuf;
+ }
+ printf ("%10s:%-8u", cp, mbstat.m_mtypes[i]);
+ if (++printed == 4) {
+ printf ("\n");
+ printed = 0;
+ }
+ }
+ }
+ if (printed)
+ printf ("\n");
+ printf ("\n");
+}
diff --git a/rtems/rtems_showroute.c b/rtems/rtems_showroute.c
new file mode 100644
index 0000000..971c364
--- /dev/null
+++ b/rtems/rtems_showroute.c
@@ -0,0 +1,240 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+
+/*
+ * We'll use the application versions of realloc and free.
+ */
+#undef free
+#undef malloc
+#undef random
+#include <stdlib.h>
+
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * Information per route
+ */
+struct rinfo {
+ struct sockaddr dst;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_dl sdl;
+ } un;
+ unsigned long pksent;
+ unsigned long expire;
+ int flags;
+ char ifname[16];
+ short ifunit;
+ short refcnt;
+};
+
+/*
+ * Information per display
+ */
+struct dinfo {
+ int capacity;
+ int count;
+ struct rinfo *routes;
+};
+
+/*
+ * Copy address
+ */
+static void
+copyAddress (void *to, void *from, int tolen)
+{
+ int ncopy;
+ struct sockaddr dummy;
+
+ if (from == NULL) {
+ /*
+ * Create a fake address of unspecified type
+ */
+ from = &dummy;
+ dummy.sa_len = 4;
+ dummy.sa_family = AF_UNSPEC;
+ }
+ ncopy = ((struct sockaddr *)from)->sa_len;
+ if (ncopy > tolen)
+ ncopy = tolen;
+ memcpy (to, from, ncopy);
+}
+
+/*
+ * Package everything up before printing it.
+ * We don't want to block all network operations till
+ * the printing completes!
+ */
+static int
+show_inet_route (
+ struct radix_node *rn,
+ void *vw )
+{
+ struct rtentry *rt = (struct rtentry *)rn;
+ struct ifnet *ifp;
+ struct dinfo *dp = (struct dinfo *)vw;
+ struct rinfo *r;
+
+ /*
+ * Get a pointer to a new route info structure
+ */
+ if (dp->count >= dp->capacity) {
+ r = realloc (dp->routes, (sizeof *r) * (dp->capacity + 20));
+ if (r == 0)
+ return ENOMEM;
+ dp->capacity += 20;
+ dp->routes = r;
+ }
+ r = dp->routes + dp->count++;
+
+ /*
+ * Fill in the route info structure
+ */
+ copyAddress (&r->dst, rt_key(rt), sizeof r->dst);
+ if (rt->rt_flags & (RTF_GATEWAY | RTF_HOST)) {
+ copyAddress (&r->un, rt->rt_gateway, sizeof r->un);
+ }
+ else {
+ /*
+ * Create a fake address to hold the mask
+ */
+ struct sockaddr_in dummy;
+
+ dummy.sin_family = AF_INET;
+ dummy.sin_len = sizeof dummy;
+ dummy.sin_addr = ((struct sockaddr_in *)rt_mask(rt))->sin_addr;
+ copyAddress (&r->un, &dummy, sizeof r->un);
+ }
+ r->flags = rt->rt_flags;
+ r->refcnt = rt->rt_refcnt;
+ r->pksent = rt->rt_rmx.rmx_pksent;
+ r->expire = rt->rt_rmx.rmx_expire;
+ ifp = rt->rt_ifp;
+ strncpy (r->ifname, (ifp->if_name ? ifp->if_name : ""), sizeof r->ifname);
+ r->ifunit = ifp->if_unit;
+ return 0;
+}
+
+/*
+ * Convert link address to ASCII
+ */
+static char *
+link_ascii (struct sockaddr_dl *sdl, char *buf, int bufsize)
+{
+ char *cp;
+ int i;
+ int first = 1;
+ int nleft = sdl->sdl_alen;
+ char *ap = LLADDR (sdl);
+ static const char hextab[16] = "0123456789ABCDEF";
+
+ cp = buf;
+ while (nleft && (bufsize > 4)) {
+ if (first) {
+ first = 0;
+ }
+ else {
+ *cp++ = ':';
+ bufsize--;
+ }
+ i = *ap++;
+ *cp++ = hextab[(i >> 4) & 0xf];
+ *cp++ = hextab[i & 0xf];
+ nleft--;
+ bufsize -= 2;
+ }
+ *cp = '\0';
+ return buf;
+}
+
+void
+rtems_bsdnet_show_inet_routes (void)
+{
+ struct radix_node_head *rnh;
+ struct dinfo d;
+ struct rinfo *r;
+ int i, error;
+
+ /*
+ * For now we'll handle only AF_INET
+ */
+ rnh = rt_tables[AF_INET];
+ if (!rnh)
+ return;
+ d.count = d.capacity = 0;
+ d.routes = NULL;
+ rtems_bsdnet_semaphore_obtain ();
+ error = rnh->rnh_walktree(rnh, show_inet_route, &d);
+ rtems_bsdnet_semaphore_release ();
+ if (error) {
+ printf ("Can't get route info: %s\n", strerror (error));
+ return;
+ }
+ if (d.count == 0) {
+ printf ("No routes!\n");
+ return;
+ }
+ printf ("Destination Gateway/Mask/Hw Flags Refs Use Expire Interface\n");
+ for (i = 0, r = d.routes ; i < d.count ; i++, r++) {
+ char buf[30];
+ char *cp, *fc, flagbuf[10];
+ const char *addr;
+ unsigned long flagbit;
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)&r->dst;
+ if (sin->sin_addr.s_addr == INADDR_ANY)
+ addr = "default";
+ else
+ addr = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof buf);
+ printf ("%-16s", addr);
+ switch (r->un.sa.sa_family) {
+ case AF_INET:
+ addr = inet_ntop (AF_INET, &r->un.sin.sin_addr, buf, sizeof buf);
+ break;
+
+ case AF_LINK:
+ addr = link_ascii (&r->un.sdl, buf, sizeof buf);
+ break;
+
+ default:
+ addr = "";
+ break;
+ }
+ printf ("%-19s", addr);
+ fc = "UGHRDM XLS";
+ for (flagbit = 0x1, cp = flagbuf ; *fc ; flagbit <<= 1, fc++) {
+ if ((r->flags & flagbit) && (*fc != ' '))
+ *cp++ = *fc;
+ }
+ *cp = '\0';
+ printf ("%-10s%3d%9ld%7ld %.*s%d\n", flagbuf,
+ r->refcnt, r->pksent,
+ r->expire,
+ (int)sizeof r->ifname, r->ifname,
+ r->ifunit);
+ }
+ free (d.routes);
+}
diff --git a/rtems/rtems_showtcpstat.c b/rtems/rtems_showtcpstat.c
new file mode 100644
index 0000000..3a17809
--- /dev/null
+++ b/rtems/rtems_showtcpstat.c
@@ -0,0 +1,106 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_var.h>
+
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * Display TCP statistics
+ * Don't lock the rest of the network tasks out while printing.
+ * It's no big deal if the values change while being printed.
+ */
+static void
+showtcpstat (const char *name, unsigned long n)
+{
+ if (n)
+ printf ("%35s%12lu\n", name, n);
+}
+
+void
+rtems_bsdnet_show_tcp_stats (void)
+{
+ printf ("************ TCP Statistics ************\n");
+ showtcpstat ("connections initiated", tcpstat.tcps_connattempt);
+ showtcpstat ("connections accepted", tcpstat.tcps_accepts);
+ showtcpstat ("connections established", tcpstat.tcps_connects);
+ showtcpstat ("connections dropped", tcpstat.tcps_drops);
+ showtcpstat ("embryonic connections dropped", tcpstat.tcps_conndrops);
+ showtcpstat ("conn. closed (includes drops)", tcpstat.tcps_closed);
+ showtcpstat ("segs where we tried to get rtt", tcpstat.tcps_segstimed);
+ showtcpstat ("times we succeeded", tcpstat.tcps_rttupdated);
+ showtcpstat ("delayed acks sent", tcpstat.tcps_delack);
+ showtcpstat ("conn. dropped in rxmt timeout", tcpstat.tcps_timeoutdrop);
+ showtcpstat ("retransmit timeouts", tcpstat.tcps_rexmttimeo);
+ showtcpstat ("persist timeouts", tcpstat.tcps_persisttimeo);
+ showtcpstat ("keepalive timeouts", tcpstat.tcps_keeptimeo);
+ showtcpstat ("keepalive probes sent", tcpstat.tcps_keepprobe);
+ showtcpstat ("connections dropped in keepalive", tcpstat.tcps_keepdrops);
+
+ showtcpstat ("total packets sent", tcpstat.tcps_sndtotal);
+ showtcpstat ("data packets sent", tcpstat.tcps_sndpack);
+ showtcpstat ("data bytes sent", tcpstat.tcps_sndbyte);
+ showtcpstat ("data packets retransmitted", tcpstat.tcps_sndrexmitpack);
+ showtcpstat ("data bytes retransmitted", tcpstat.tcps_sndrexmitbyte);
+ showtcpstat ("ack-only packets sent", tcpstat.tcps_sndacks);
+ showtcpstat ("window probes sent", tcpstat.tcps_sndprobe);
+ showtcpstat ("packets sent with URG only", tcpstat.tcps_sndurg);
+ showtcpstat ("window update-only packets sent", tcpstat.tcps_sndwinup);
+ showtcpstat ("control (SYN|FIN|RST) packets sent", tcpstat.tcps_sndctrl);
+
+ showtcpstat ("total packets received", tcpstat.tcps_rcvtotal);
+ showtcpstat ("packets received in sequence", tcpstat.tcps_rcvpack);
+ showtcpstat ("bytes received in sequence", tcpstat.tcps_rcvbyte);
+ showtcpstat ("packets received with ccksum errs", tcpstat.tcps_rcvbadsum);
+ showtcpstat ("packets received with bad offset", tcpstat.tcps_rcvbadoff);
+ showtcpstat ("packets received too short", tcpstat.tcps_rcvshort);
+ showtcpstat ("duplicate-only packets received", tcpstat.tcps_rcvduppack);
+ showtcpstat ("duplicate-only bytes received", tcpstat.tcps_rcvdupbyte);
+ showtcpstat ("packets with some duplicate data", tcpstat.tcps_rcvpartduppack);
+ showtcpstat ("dup. bytes in part-dup. packets", tcpstat.tcps_rcvpartdupbyte);
+ showtcpstat ("out-of-order packets received", tcpstat.tcps_rcvoopack);
+ showtcpstat ("out-of-order bytes received", tcpstat.tcps_rcvoobyte);
+ showtcpstat ("packets with data after window", tcpstat.tcps_rcvpackafterwin);
+ showtcpstat ("bytes rcvd after window", tcpstat.tcps_rcvbyteafterwin);
+ showtcpstat ("packets rcvd after \"close\"", tcpstat.tcps_rcvafterclose);
+ showtcpstat ("rcvd window probe packets", tcpstat.tcps_rcvwinprobe);
+ showtcpstat ("rcvd duplicate acks", tcpstat.tcps_rcvdupack);
+ showtcpstat ("rcvd acks for unsent data", tcpstat.tcps_rcvacktoomuch);
+ showtcpstat ("rcvd ack packets", tcpstat.tcps_rcvackpack);
+ showtcpstat ("bytes acked by rcvd acks", tcpstat.tcps_rcvackbyte);
+ showtcpstat ("rcvd window update packets", tcpstat.tcps_rcvwinupd);
+ showtcpstat ("segments dropped due to PAWS", tcpstat.tcps_pawsdrop);
+ showtcpstat ("times hdr predict ok for acks", tcpstat.tcps_predack);
+ showtcpstat ("times hdr predict ok for data pkts", tcpstat.tcps_preddat);
+ showtcpstat ("pcb cache misses", tcpstat.tcps_pcbcachemiss);
+ showtcpstat ("times cached RTT in route updated", tcpstat.tcps_cachedrtt);
+ showtcpstat ("times cached rttvar updated", tcpstat.tcps_cachedrttvar);
+ showtcpstat ("times cached ssthresh updated", tcpstat.tcps_cachedssthresh);
+ showtcpstat ("times RTT initialized from route", tcpstat.tcps_usedrtt);
+ showtcpstat ("times RTTVAR initialized from rt", tcpstat.tcps_usedrttvar);
+ showtcpstat ("times ssthresh initialized from rt", tcpstat.tcps_usedssthresh);
+ showtcpstat ("timeout in persist state", tcpstat.tcps_persistdrop);
+ showtcpstat ("bogus SYN, e.g. premature ACK", tcpstat.tcps_badsyn);
+ showtcpstat ("resends due to MTU discovery", tcpstat.tcps_mturesent);
+ showtcpstat ("listen queue overflows", tcpstat.tcps_listendrop);
+ printf ("\n");
+}
diff --git a/rtems/rtems_showudpstat.c b/rtems/rtems_showudpstat.c
new file mode 100644
index 0000000..c6b4560
--- /dev/null
+++ b/rtems/rtems_showudpstat.c
@@ -0,0 +1,52 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <rtems/rtems_bsdnet.h>
+
+/*
+ * Display UDP statistics
+ * Don't lock the rest of the network tasks out while printing.
+ * It's no big deal if the values change while being printed.
+ */
+static void
+showudpstat (const char *name, unsigned long n)
+{
+ if (n)
+ printf ("%35s%12lu\n", name, n);
+}
+
+void
+rtems_bsdnet_show_udp_stats (void)
+{
+ printf ("************ UDP Statistics ************\n");
+ showudpstat ("total input packets", udpstat.udps_ipackets);
+ showudpstat ("packet shorter than header", udpstat.udps_hdrops);
+ showudpstat ("checksum error", udpstat.udps_badsum);
+ showudpstat ("data length larger than packet", udpstat.udps_badlen);
+ showudpstat ("no socket on port", udpstat.udps_noport);
+ showudpstat ("of above, arrived as broadcast", udpstat.udps_noportbcast);
+ showudpstat ("not delivered, input socket full", udpstat.udps_fullsock);
+ showudpstat ("input packets missing pcb cache", udpstat.udpps_pcbcachemiss);
+ showudpstat ("input packets not for hashed pcb", udpstat.udpps_pcbhashmiss);
+ showudpstat ("total output packets", udpstat.udps_opackets);
+ printf ("\n");
+}
diff --git a/rtems/rtems_socketpair.c b/rtems/rtems_socketpair.c
new file mode 100644
index 0000000..1dcaf6e
--- /dev/null
+++ b/rtems/rtems_socketpair.c
@@ -0,0 +1,53 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * socketpair() for RTEMS
+ *
+ * This file exists primarily to document what is required to provide
+ * a functional implementation of socketpair() for RTEMS.
+ *
+ * The socketpair() service requires that the "local domain" sockets
+ * be functional. This is denoted by the domain constants AF_LOCAL
+ * and AF_UNIX and the protocol constants PF_LOCAL and PF_UNIX. The
+ * local domain functionality is implemented in the file kern/uipc_usrreq.c
+ * which was not part of the initial port of the FreeBSD stack to
+ * RTEMS.
+ *
+ * The FreeBSD socketpair implementation appears to be dependent on
+ * file system features which are not available currently in RTEMS.
+ *
+ * COPYRIGHT (c) 1989-2007.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include "rtems_syscall.h"
+
+int socketpair (int domain, int type, int protocol, int *rsv)
+{
+ if ( !rsv ) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ /*
+ * Yes, we do not support socketpair() so this is really paranoid.
+ * But it ensures that someone calling this routine and ignoring
+ * the return status will get errors from subsequent socket calls.
+ */
+ rsv[ 0 ] = -1;
+ rsv[ 1 ] = -1;
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/rtems/rtems_syscall.c b/rtems/rtems_syscall.c
new file mode 100644
index 0000000..7f3143b
--- /dev/null
+++ b/rtems/rtems_syscall.c
@@ -0,0 +1,835 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+/* #include <stdlib.h> */
+#include <stdio.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/filio.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+
+#include "rtems_syscall.h"
+
+/*
+ * Hooks to RTEMS I/O system
+ */
+static const rtems_filesystem_file_handlers_r socket_handlers;
+
+/*
+ * Convert an RTEMS file descriptor to a BSD socket pointer.
+ */
+struct socket *
+rtems_bsdnet_fdToSocket (int fd)
+{
+ rtems_libio_t *iop;
+
+ if ((uint32_t)fd >= rtems_libio_number_iops) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ iop = rtems_libio_iop(fd);
+
+ if ((rtems_libio_iop_flags(iop) & LIBIO_FLAGS_OPEN) == 0) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ if (iop->pathinfo.handlers != &socket_handlers) {
+ errno = ENOTSOCK;
+ return NULL;
+ }
+
+ if (iop->data1 == NULL)
+ errno = EBADF;
+ return iop->data1;
+}
+
+/*
+ * Create an RTEMS file descriptor for a socket
+ */
+static int
+rtems_bsdnet_makeFdForSocket (void *so)
+{
+ rtems_libio_t *iop;
+ int fd;
+
+ iop = rtems_libio_allocate();
+ if (iop == 0)
+ rtems_set_errno_and_return_minus_one( ENFILE );
+
+ fd = rtems_libio_iop_to_descriptor(iop);
+ iop->data0 = fd;
+ iop->data1 = so;
+ iop->pathinfo.handlers = &socket_handlers;
+ iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry;
+ rtems_filesystem_location_add_to_mt_entry(&iop->pathinfo);
+ rtems_libio_iop_flags_set(iop, LIBIO_FLAGS_OPEN | LIBIO_FLAGS_READ_WRITE);
+ return fd;
+}
+
+/*
+ * Package system call argument into mbuf.
+ */
+static int
+sockargstombuf (struct mbuf **mp, const void *buf, int buflen, int type)
+{
+ struct mbuf *m;
+
+ if ((u_int)buflen > MLEN)
+ return (EINVAL);
+ m = m_get(M_WAIT, type);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = buflen;
+ memcpy (mtod(m, caddr_t), buf, buflen);
+ *mp = m;
+ if (type == MT_SONAME) {
+ struct sockaddr *sa;
+ sa = mtod(m, struct sockaddr *);
+ sa->sa_len = buflen;
+ }
+ return 0;
+}
+
+/*
+ *********************************************************************
+ * BSD-style entry points *
+ *********************************************************************
+ */
+int
+socket (int domain, int type, int protocol)
+{
+ int fd;
+ int error;
+ struct socket *so;
+
+ rtems_bsdnet_semaphore_obtain ();
+ error = socreate(domain, &so, type, protocol, NULL);
+ if (error == 0) {
+ fd = rtems_bsdnet_makeFdForSocket (so);
+ if (fd < 0)
+ soclose (so);
+ }
+ else {
+ errno = error;
+ fd = -1;
+ }
+ rtems_bsdnet_semaphore_release ();
+ return fd;
+}
+
+int
+bind (int s, const struct sockaddr *name, socklen_t namelen)
+{
+ int error;
+ int ret = -1;
+ struct socket *so;
+ struct mbuf *nam;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) {
+ error = sockargstombuf (&nam, name, namelen, MT_SONAME);
+ if (error == 0) {
+ error = sobind (so, nam);
+ if (error == 0)
+ ret = 0;
+ else
+ errno = error;
+ m_freem (nam);
+ }
+ else {
+ errno = error;
+ }
+ }
+ rtems_bsdnet_semaphore_release ();
+ return ret;
+}
+
+int
+connect (int s, const struct sockaddr *name, socklen_t namelen)
+{
+ int error;
+ int ret = -1;
+ struct socket *so;
+ struct mbuf *nam;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
+ errno = EALREADY;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ error = sockargstombuf (&nam, name, namelen, MT_SONAME);
+ if (error) {
+ errno = error;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ error = soconnect (so, nam);
+ if (error)
+ goto bad;
+ if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
+ m_freem(nam);
+ errno = EINPROGRESS;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ error = so->so_error;
+ while (error == 0 && (so->so_state & SS_ISCONNECTING)) {
+ error = soconnsleep (so);
+ if (error)
+ break;
+ error = so->so_error;
+ so->so_error = 0;
+ }
+ bad:
+ if (error != ENXIO)
+ so->so_state &= ~SS_ISCONNECTING;
+ m_freem (nam);
+ if (error)
+ errno = error;
+ else
+ ret = 0;
+ rtems_bsdnet_semaphore_release ();
+ return ret;
+}
+
+int
+listen (int s, int backlog)
+{
+ int error;
+ int ret = -1;
+ struct socket *so;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) {
+ error = solisten (so, backlog);
+ if (error == 0)
+ ret = 0;
+ else
+ errno = error;
+ }
+ rtems_bsdnet_semaphore_release ();
+ return ret;
+}
+
+int
+accept (int s, struct sockaddr *name, socklen_t *namelen)
+{
+ int fd;
+ struct socket *head, *so;
+ struct mbuf *nam;
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((head = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if ((head->so_options & SO_ACCEPTCONN) == 0) {
+ errno = EINVAL;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) {
+ errno = EWOULDBLOCK;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ error = head->so_error;
+ while (error == 0 && head->so_comp.tqh_first == NULL) {
+ if (head->so_state & SS_CANTRCVMORE) {
+ error = ECONNABORTED;
+ break;
+ }
+ error = soconnsleep (head);
+ }
+ if (error) {
+ errno = error;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+
+ so = head->so_comp.tqh_first;
+ TAILQ_REMOVE(&head->so_comp, so, so_list);
+ head->so_qlen--;
+
+ fd = rtems_bsdnet_makeFdForSocket (so);
+ if (fd < 0) {
+ TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
+ head->so_qlen++;
+ soconnwakeup (head);
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ so->so_state &= ~SS_COMP;
+ so->so_head = NULL;
+
+ nam = m_get(M_WAIT, MT_SONAME);
+ (void) soaccept(so, nam);
+ if (name) {
+ /* check length before it is destroyed */
+ if (*namelen > nam->m_len)
+ *namelen = nam->m_len;
+ memcpy (name, mtod(nam, caddr_t), *namelen);
+ }
+ m_freem(nam);
+ rtems_bsdnet_semaphore_release ();
+ return (fd);
+
+}
+
+/*
+ * Shutdown routine
+ */
+
+int
+shutdown (int s, int how)
+{
+ struct socket *so;
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ error = soshutdown(so, how);
+ rtems_bsdnet_semaphore_release ();
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * All `transmit' operations end up calling this routine.
+ */
+ssize_t
+sendmsg (int s, const struct msghdr *mp, int flags)
+{
+ int ret = -1;
+ int error;
+ struct uio auio;
+ struct iovec *iov;
+ struct socket *so;
+ struct mbuf *to;
+ struct mbuf *control = NULL;
+ int i;
+ int len;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ auio.uio_iov = mp->msg_iov;
+ auio.uio_iovcnt = mp->msg_iovlen;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_rw = UIO_WRITE;
+ auio.uio_offset = 0;
+ auio.uio_resid = 0;
+ iov = mp->msg_iov;
+ for (i = 0; i < mp->msg_iovlen; i++, iov++) {
+ if ((auio.uio_resid += iov->iov_len) < 0) {
+ errno = EINVAL;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ }
+ if (mp->msg_name) {
+ error = sockargstombuf (&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
+ if (error) {
+ errno = error;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ }
+ else {
+ to = NULL;
+ }
+ if (mp->msg_control) {
+ if (mp->msg_controllen < sizeof (struct cmsghdr)) {
+ errno = EINVAL;
+ if (to)
+ m_freem(to);
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ sockargstombuf (&control, mp->msg_control, mp->msg_controllen, MT_CONTROL);
+ }
+ else {
+ control = NULL;
+ }
+ len = auio.uio_resid;
+ error = sosend (so, to, &auio, (struct mbuf *)0, control, flags);
+ if (error) {
+ if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
+ error = 0;
+ }
+ if (error)
+ errno = error;
+ else
+ ret = len - auio.uio_resid;
+ if (to)
+ m_freem(to);
+ rtems_bsdnet_semaphore_release ();
+ return (ret);
+}
+
+/*
+ * Send a message to a host
+ */
+ssize_t
+sendto (int s, const void *buf, size_t buflen, int flags, const struct sockaddr *to, socklen_t tolen)
+{
+ struct msghdr msg;
+ struct iovec iov;
+
+ iov.iov_base = (void *)buf;
+ iov.iov_len = buflen;
+ msg.msg_name = (caddr_t)to;
+ msg.msg_namelen = tolen;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ return sendmsg (s, &msg, flags);
+}
+
+/*
+ * All `receive' operations end up calling this routine.
+ */
+ssize_t
+recvmsg (int s, struct msghdr *mp, int flags)
+{
+ int ret = -1;
+ int error;
+ struct uio auio;
+ struct iovec *iov;
+ struct socket *so;
+ struct mbuf *from = NULL, *control = NULL;
+ int i;
+ int len;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ auio.uio_iov = mp->msg_iov;
+ auio.uio_iovcnt = mp->msg_iovlen;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_rw = UIO_READ;
+ auio.uio_offset = 0;
+ auio.uio_resid = 0;
+ iov = mp->msg_iov;
+ for (i = 0; i < mp->msg_iovlen; i++, iov++) {
+ if ((auio.uio_resid += iov->iov_len) < 0) {
+ errno = EINVAL;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ }
+ len = auio.uio_resid;
+ mp->msg_flags = flags;
+ error = soreceive (so, &from, &auio, (struct mbuf **)NULL,
+ mp->msg_control ? &control : (struct mbuf **)NULL,
+ &mp->msg_flags);
+ if (error) {
+ if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
+ error = 0;
+ }
+ if (error) {
+ errno = error;
+ }
+ else {
+ ret = len - auio.uio_resid;
+ if (mp->msg_name) {
+ len = mp->msg_namelen;
+ if ((len <= 0) || (from == NULL)) {
+ len = 0;
+ }
+ else {
+ if (len > from->m_len)
+ len = from->m_len;
+ memcpy (mp->msg_name, mtod(from, caddr_t), len);
+ }
+ mp->msg_namelen = len;
+ }
+ if (mp->msg_control) {
+ struct mbuf *m;
+ void *ctlbuf;
+
+ len = mp->msg_controllen;
+ m = control;
+ mp->msg_controllen = 0;
+ ctlbuf = mp->msg_control;
+
+ while (m && (len > 0)) {
+ unsigned int tocopy;
+
+ if (len >= m->m_len)
+ tocopy = m->m_len;
+ else {
+ mp->msg_flags |= MSG_CTRUNC;
+ tocopy = len;
+ }
+ memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
+ ctlbuf += tocopy;
+ len -= tocopy;
+ m = m->m_next;
+ }
+ mp->msg_controllen = ctlbuf - mp->msg_control;
+ }
+ }
+ if (from)
+ m_freem (from);
+ if (control)
+ m_freem (control);
+ rtems_bsdnet_semaphore_release ();
+ return (ret);
+}
+
+/*
+ * Receive a message from a host
+ */
+ssize_t
+recvfrom (int s, void *buf, size_t buflen, int flags, struct sockaddr *from, socklen_t *fromlen)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ int ret;
+
+ iov.iov_base = buf;
+ iov.iov_len = buflen;
+ msg.msg_name = (caddr_t)from;
+ if (fromlen)
+ msg.msg_namelen = *fromlen;
+ else
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ ret = recvmsg (s, &msg, flags);
+ if ((from != NULL) && (fromlen != NULL) && (ret >= 0))
+ *fromlen = msg.msg_namelen;
+ return ret;
+}
+
+int
+setsockopt (int s, int level, int name, const void *val, socklen_t len)
+{
+ struct socket *so;
+ struct mbuf *m = NULL;
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if (len > MLEN) {
+ errno = EINVAL;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if (val) {
+ error = sockargstombuf (&m, val, len, MT_SOOPTS);
+ if (error) {
+ errno = error;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ }
+ error = sosetopt(so, level, name, m);
+ if (error) {
+ errno = error;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ rtems_bsdnet_semaphore_release ();
+ return 0;
+}
+
+int
+getsockopt (int s, int level, int name, void *aval, socklen_t *avalsize)
+{
+ struct socket *so;
+ struct mbuf *m = NULL, *m0;
+ char *val = aval;
+ int i, op, valsize;
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if (val)
+ valsize = *avalsize;
+ else
+ valsize = 0;
+ if (((error = sogetopt(so, level, name, &m)) == 0) && val && valsize && m) {
+ op = 0;
+ while (m && op < valsize) {
+ i = valsize - op;
+ if (i > m->m_len)
+ i = m->m_len;
+ memcpy (val, mtod(m, caddr_t), i);
+ op += i;
+ val += i;
+ m0 = m;
+ MFREE (m0, m);
+ }
+ *avalsize = op;
+ }
+ if (m != NULL)
+ (void) m_free(m);
+ if (error) {
+ errno = error;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ rtems_bsdnet_semaphore_release ();
+ return 0;
+}
+
+static int
+getpeersockname (int s, struct sockaddr *name, socklen_t *namelen, int pflag)
+{
+ struct socket *so;
+ struct mbuf *m;
+ int len = *namelen;
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ m = m_getclr(M_WAIT, MT_SONAME);
+ if (m == NULL) {
+ errno = ENOBUFS;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if (pflag)
+ error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m);
+ else
+ error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m);
+ if (error) {
+ m_freem(m);
+ errno = error;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ if (len > m->m_len) {
+ len = m->m_len;
+ *namelen = len;
+ }
+ memcpy (name, mtod(m, caddr_t), len);
+ m_freem (m);
+ rtems_bsdnet_semaphore_release ();
+ return 0;
+}
+
+int
+getpeername (int s, struct sockaddr *name, socklen_t *namelen)
+{
+ return getpeersockname (s, name, namelen, 1);
+}
+int
+getsockname (int s, struct sockaddr *name, socklen_t *namelen)
+{
+ return getpeersockname (s, name, namelen, 0);
+}
+
+int
+sysctl(const int *name, u_int namelen, void *oldp,
+ size_t *oldlenp, const void *newp, size_t newlen)
+{
+ int error;
+ size_t j;
+
+ rtems_bsdnet_semaphore_obtain ();
+ error = userland_sysctl (0, name, namelen, oldp, oldlenp, 1, newp, newlen, &j);
+ rtems_bsdnet_semaphore_release ();
+
+ if (oldlenp)
+ *oldlenp = j;
+
+ if (error)
+ {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ ************************************************************************
+ * RTEMS I/O HANDLER ROUTINES *
+ ************************************************************************
+ */
+static int
+rtems_bsdnet_close (rtems_libio_t *iop)
+{
+ struct socket *so;
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = iop->data1) == NULL) {
+ errno = EBADF;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ iop->data1 = NULL;
+ error = soclose (so);
+ rtems_bsdnet_semaphore_release ();
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+static ssize_t
+rtems_bsdnet_read (rtems_libio_t *iop, void *buffer, size_t count)
+{
+ return recv (iop->data0, buffer, count, 0);
+}
+
+static ssize_t
+rtems_bsdnet_write (rtems_libio_t *iop, const void *buffer, size_t count)
+{
+ return send (iop->data0, buffer, count, 0);
+}
+
+static int
+so_ioctl (rtems_libio_t *iop, struct socket *so, uint32_t command, void *buffer)
+{
+ unsigned int nonblock;
+
+ switch (command) {
+ case FIONBIO:
+ nonblock = rtems_libio_fcntl_flags (O_NONBLOCK);
+
+ if (*(int *)buffer) {
+ rtems_libio_iop_flags_set (iop, nonblock);
+ so->so_state |= SS_NBIO;
+ }
+ else {
+ rtems_libio_iop_flags_clear (iop, nonblock);
+ so->so_state &= ~SS_NBIO;
+ }
+ return 0;
+
+ case FIONREAD:
+ *(int *)buffer = so->so_rcv.sb_cc;
+ return 0;
+ }
+
+ if (IOCGROUP(command) == 'i')
+ return ifioctl (so, command, buffer, NULL);
+ if (IOCGROUP(command) == 'r')
+ return rtioctl (command, buffer, NULL);
+ return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0);
+}
+
+static int
+rtems_bsdnet_ioctl (rtems_libio_t *iop, ioctl_command_t command, void *buffer)
+{
+ struct socket *so;
+ int error;
+
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = iop->data1) == NULL) {
+ errno = EBADF;
+ rtems_bsdnet_semaphore_release ();
+ return -1;
+ }
+ error = so_ioctl (iop, so, command, buffer);
+ rtems_bsdnet_semaphore_release ();
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+static int
+rtems_bsdnet_fcntl (rtems_libio_t *iop, int cmd)
+{
+ struct socket *so;
+
+ if (cmd == F_SETFL) {
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = iop->data1) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return EBADF;
+ }
+ if (rtems_libio_iop_is_no_delay(iop))
+ so->so_state |= SS_NBIO;
+ else
+ so->so_state &= ~SS_NBIO;
+ rtems_bsdnet_semaphore_release ();
+ }
+ return 0;
+}
+
+static int
+rtems_bsdnet_fstat (const rtems_filesystem_location_info_t *loc, struct stat *sp)
+{
+ sp->st_mode = S_IFSOCK;
+ return 0;
+}
+
+static const rtems_filesystem_file_handlers_r socket_handlers = {
+ .open_h = rtems_filesystem_default_open,
+ .close_h = rtems_bsdnet_close,
+ .read_h = rtems_bsdnet_read,
+ .write_h = rtems_bsdnet_write,
+ .ioctl_h = rtems_bsdnet_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek,
+ .fstat_h = rtems_bsdnet_fstat,
+ .ftruncate_h = rtems_filesystem_default_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fcntl_h = rtems_bsdnet_fcntl,
+ .kqfilter_h = rtems_filesystem_default_kqfilter,
+ .mmap_h = rtems_filesystem_default_mmap,
+ .poll_h = rtems_filesystem_default_poll,
+ .readv_h = rtems_filesystem_default_readv,
+ .writev_h = rtems_filesystem_default_writev
+};
diff --git a/rtems/rtems_syscall.h b/rtems/rtems_syscall.h
new file mode 100644
index 0000000..b0d38a6
--- /dev/null
+++ b/rtems/rtems_syscall.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef _LIBNETWORKING_RTEMS_SYSCALL_H_
+#define _LIBNETWORKING_RTEMS_SYSCALL_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+int accept(int, struct sockaddr * __restrict, socklen_t * __restrict);
+
+int bind(int, const struct sockaddr *, socklen_t);
+
+int connect(int, const struct sockaddr *, socklen_t);
+
+int getpeername(int, struct sockaddr * __restrict, socklen_t * __restrict);
+
+int getsockname(int, struct sockaddr * __restrict, socklen_t * __restrict);
+
+int getsockopt(int, int, int, void * __restrict, socklen_t * __restrict);
+
+int listen(int, int);
+
+ssize_t recv(int, void *, size_t, int);
+
+ssize_t recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict);
+
+ssize_t recvmsg(int, struct msghdr *, int);
+
+ssize_t send(int, const void *, size_t, int);
+
+ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
+
+ssize_t sendmsg(int, const struct msghdr *, int);
+
+int setsockopt(int, int, int, const void *, socklen_t);
+
+int shutdown(int, int);
+
+int socket(int, int, int);
+
+int socketpair(int, int, int, int *);
+
+int sysctl(const int *, u_int, void *, size_t *, const void *, size_t);
+
+int sysctlbyname(const char *, void *, size_t *, const void *, size_t);
+
+int sysctlnametomib(const char *, int *, size_t *);
+
+__END_DECLS
+
+#endif /* _LIBNETWORKING_RTEMS_SYSCALL_H_ */
diff --git a/rtems/rtems_syscall_api.c b/rtems/rtems_syscall_api.c
new file mode 100644
index 0000000..6899eba
--- /dev/null
+++ b/rtems/rtems_syscall_api.c
@@ -0,0 +1,22 @@
+#include <machine/rtems-bsd-user-space.h>
+
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Ensure that kernel and user space system call protoypes are identical */
+#include "rtems_syscall.h"
diff --git a/rtems/sghostname.c b/rtems/sghostname.c
new file mode 100644
index 0000000..df7513d
--- /dev/null
+++ b/rtems/sghostname.c
@@ -0,0 +1,54 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * RTEMS versions of hostname functions
+ * FIXME: Not thread-safe
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <rtems/rtems_bsdnet.h>
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+
+static char *rtems_hostname;
+
+int
+gethostname (char *name, size_t namelen)
+{
+ char *cp = rtems_hostname;
+
+ if (cp == NULL)
+ cp = "";
+ strncpy (name, cp, namelen);
+ return 0;
+}
+
+int
+sethostname (const char *name, size_t namelen)
+{
+ char *old, *new;
+
+ if (namelen >= MAXHOSTNAMELEN) {
+ errno = EINVAL;
+ return -1;
+ }
+ new = malloc (namelen + 1, M_HTABLE, M_NOWAIT);
+ if (new == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ strncpy (new, name, namelen);
+ new[namelen] = '\0';
+ old = rtems_hostname;
+ rtems_hostname = new;
+ if (old)
+ free (old, M_HTABLE);
+ return 0;
+}