summaryrefslogtreecommitdiffstats
path: root/cpukit/libnetworking/rtems
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libnetworking/rtems')
-rw-r--r--cpukit/libnetworking/rtems/bsdnet/_types.h44
-rw-r--r--cpukit/libnetworking/rtems/bsdnet/servers.h21
-rw-r--r--cpukit/libnetworking/rtems/dhcp.h49
-rw-r--r--cpukit/libnetworking/rtems/ftpfs.h162
-rw-r--r--cpukit/libnetworking/rtems/mkrootfs.c246
-rw-r--r--cpukit/libnetworking/rtems/mkrootfs.h81
-rw-r--r--cpukit/libnetworking/rtems/rtems_bootp.c42
-rw-r--r--cpukit/libnetworking/rtems/rtems_bsdnet.h317
-rw-r--r--cpukit/libnetworking/rtems/rtems_bsdnet_internal.h205
-rw-r--r--cpukit/libnetworking/rtems/rtems_bsdnet_malloc_starvation.c19
-rw-r--r--cpukit/libnetworking/rtems/rtems_dhcp.c1231
-rw-r--r--cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c372
-rw-r--r--cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h29
-rw-r--r--cpukit/libnetworking/rtems/rtems_glue.c1310
-rw-r--r--cpukit/libnetworking/rtems/rtems_malloc_mbuf.c39
-rw-r--r--cpukit/libnetworking/rtems/rtems_mii_ioctl.c172
-rw-r--r--cpukit/libnetworking/rtems/rtems_mii_ioctl.h141
-rw-r--r--cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c259
-rw-r--r--cpukit/libnetworking/rtems/rtems_select.c178
-rw-r--r--cpukit/libnetworking/rtems/rtems_showicmpstat.c70
-rw-r--r--cpukit/libnetworking/rtems/rtems_showifstat.c157
-rw-r--r--cpukit/libnetworking/rtems/rtems_showipstat.c63
-rw-r--r--cpukit/libnetworking/rtems/rtems_showmbuf.c69
-rw-r--r--cpukit/libnetworking/rtems/rtems_showroute.c240
-rw-r--r--cpukit/libnetworking/rtems/rtems_showtcpstat.c106
-rw-r--r--cpukit/libnetworking/rtems/rtems_showudpstat.c52
-rw-r--r--cpukit/libnetworking/rtems/rtems_socketpair.c51
-rw-r--r--cpukit/libnetworking/rtems/rtems_syscall.c782
-rw-r--r--cpukit/libnetworking/rtems/sghostname.c53
-rw-r--r--cpukit/libnetworking/rtems/tftp.h45
30 files changed, 6605 insertions, 0 deletions
diff --git a/cpukit/libnetworking/rtems/bsdnet/_types.h b/cpukit/libnetworking/rtems/bsdnet/_types.h
new file mode 100644
index 0000000000..3f600ff670
--- /dev/null
+++ b/cpukit/libnetworking/rtems/bsdnet/_types.h
@@ -0,0 +1,44 @@
+/*-
+ * 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 $
+ */
+
+/*
+ * $Id$
+ */
+
+#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/cpukit/libnetworking/rtems/bsdnet/servers.h b/cpukit/libnetworking/rtems/bsdnet/servers.h
new file mode 100644
index 0000000000..ca6c702cea
--- /dev/null
+++ b/cpukit/libnetworking/rtems/bsdnet/servers.h
@@ -0,0 +1,21 @@
+/**
+ * @file rtems/rtems_bsdnet.h
+ */
+
+/*
+ * $Id$
+ */
+
+#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/cpukit/libnetworking/rtems/dhcp.h b/cpukit/libnetworking/rtems/dhcp.h
new file mode 100644
index 0000000000..b29fc66c65
--- /dev/null
+++ b/cpukit/libnetworking/rtems/dhcp.h
@@ -0,0 +1,49 @@
+/*
+ ------------------------------------------------------------------------
+ $Id$
+ ------------------------------------------------------------------------
+
+ 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/cpukit/libnetworking/rtems/ftpfs.h b/cpukit/libnetworking/rtems/ftpfs.h
new file mode 100644
index 0000000000..0bb500229d
--- /dev/null
+++ b/cpukit/libnetworking/rtems/ftpfs.h
@@ -0,0 +1,162 @@
+/**
+ * @file
+ *
+ * @brief File Transfer Protocol file system (FTP client).
+ */
+
+/*
+ * Copyright (c) 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * (c) Copyright 2002
+ * Thomas Doerfler
+ * IMD Ingenieurbuero fuer Microcomputertechnik
+ * Herbststr. 8
+ * 82178 Puchheim, Germany
+ * <Thomas.Doerfler@imd-systems.de>
+ *
+ * Modified by Sebastian Huber <sebastian.huber@embedded-brains.de>.
+ *
+ * This code has been created after closly inspecting "tftpdriver.c" from Eric
+ * Norum.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#ifndef _RTEMS_FTPFS_H
+#define _RTEMS_FTPFS_H
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <rtems/libio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup rtems_ftpfs File Transfer Protocol File System
+ *
+ * @brief The FTP file system (FTP client) can be used to transfer files from
+ * or to remote hosts.
+ *
+ * You can mount the FTP file system with a call to mount() or
+ * mount_and_make_target_path() with the @ref RTEMS_FILESYSTEM_TYPE_FTPFS file
+ * system type.
+ *
+ * You have to add @ref CONFIGURE_FILESYSTEM_FTPFS to your application
+ * configuration.
+ *
+ * You can open files either read-only or write-only. A seek is not allowed.
+ * A close terminates the control and data connections.
+ *
+ * To open a file @c file.txt in the directory @c dir (relative to home
+ * directory of the server) on a server named @c host using the user name
+ * @c user and the password @c pw you must specify the following path:
+ * <tt>/FTP/user:pw@@host/dir/file.txt</tt>.
+ *
+ * If the server is the default server specified in BOOTP, it can be ommitted:
+ * <tt>/FTP/user:pw/dir/file.txt</tt>.
+ *
+ * The user name will be used for the password if it is ommitted:
+ * <tt>/FTP/user@@host/dir/file.txt</tt>.
+ *
+ * For the data transfer passive (= default) and active (= fallback) mode are
+ * supported.
+ *
+ * @{
+ */
+
+/**
+ * @brief Well-known port number for FTP control connection.
+ */
+#define RTEMS_FTPFS_CTRL_PORT 21
+
+/**
+ * @brief Default mount point for FTP file system.
+ */
+#define RTEMS_FTPFS_MOUNT_POINT_DEFAULT "/FTP"
+
+/**
+ * @brief FTP file system IO control requests.
+ */
+typedef enum {
+ RTEMS_FTPFS_IOCTL_GET_VERBOSE = _IOR( 'd', 1, bool *),
+ RTEMS_FTPFS_IOCTL_SET_VERBOSE = _IOW( 'd', 1, bool *),
+ RTEMS_FTPFS_IOCTL_GET_TIMEOUT = _IOR( 'd', 2, struct timeval *),
+ RTEMS_FTPFS_IOCTL_SET_TIMEOUT = _IOW( 'd', 2, struct timeval *)
+} rtems_ftpfs_ioctl_numbers;
+
+/**
+ * @brief Returns in @a verbose if the verbose mode is enabled or disabled for
+ * the file system at @a mount_point.
+ *
+ * If @a mount_point is @c NULL the default mount point
+ * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used.
+ */
+rtems_status_code rtems_ftpfs_get_verbose( const char *mount_point, bool *verbose);
+
+/**
+ * @brief Enables or disables the verbose mode if @a verbose is @c true or
+ * @c false respectively for the file system at @a mount_point.
+ *
+ * In the enabled verbose mode the commands and replies of the FTP control
+ * connections will be printed to standard error.
+ *
+ * If @a mount_point is @c NULL the default mount point
+ * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used.
+ */
+rtems_status_code rtems_ftpfs_set_verbose( const char *mount_point, bool verbose);
+
+/**
+ * @brief Returns the current timeout value in @a timeout for the file system
+ * at @a mount_point.
+ *
+ * If @a mount_point is @c NULL the default mount point
+ * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used.
+ */
+rtems_status_code rtems_ftpfs_get_timeout(
+ const char *mount_point,
+ struct timeval *timeout
+);
+
+/**
+ * @brief Sets the timeout value to @a timeout for the file system at
+ * @a mount_point.
+ *
+ * The timeout value will be used during connection establishment of active
+ * data connections. It will be also used for send and receive operations on
+ * data and control connections.
+ *
+ * If @a mount_point is @c NULL the default mount point
+ * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used.
+ */
+rtems_status_code rtems_ftpfs_set_timeout(
+ const char *mount_point,
+ const struct timeval *timeout
+);
+
+/** @} */
+
+/**
+ * @brief Do not call directly, use mount().
+ */
+int rtems_ftpfs_initialize(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ const void *data
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libnetworking/rtems/mkrootfs.c b/cpukit/libnetworking/rtems/mkrootfs.c
new file mode 100644
index 0000000000..63d67e26b3
--- /dev/null
+++ b/cpukit/libnetworking/rtems/mkrootfs.c
@@ -0,0 +1,246 @@
+/*
+ ------------------------------------------------------------------------
+ $Id$
+ ------------------------------------------------------------------------
+
+ 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.com/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.
+
+ */
+
+#if 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 <arpa/inet.h>
+
+#include <rtems/mkrootfs.h>
+#include <rtems/libio.h>
+
+/*
+ * A table a list of names and their modes.
+ */
+
+typedef struct rtems_rootfs_dir_table
+{
+ const char *name;
+ int 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.
+ */
+
+ int 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++)
+ {
+ int 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))
+ {
+ snprintf (bufp, sizeof (buf), "%s\t\t%s", inet_ntoa (ip), 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];
+ int 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/cpukit/libnetworking/rtems/mkrootfs.h b/cpukit/libnetworking/rtems/mkrootfs.h
new file mode 100644
index 0000000000..8bf053bc52
--- /dev/null
+++ b/cpukit/libnetworking/rtems/mkrootfs.h
@@ -0,0 +1,81 @@
+/**
+ * @file rtems/mkrootfs.h
+ *
+ * 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.com/license/LICENSE.
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+
+ $Id$
+*/
+
+#ifndef _RTEMS_MKROOTFS_H
+#define _RTEMS_MKROOTFS_H
+
+#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/cpukit/libnetworking/rtems/rtems_bootp.c b/cpukit/libnetworking/rtems/rtems_bootp.c
new file mode 100644
index 0000000000..caf2faa6e2
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_bootp.c
@@ -0,0 +1,42 @@
+/*
+ * $Id$
+ */
+
+#if 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>
+
+/*
+ * 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/cpukit/libnetworking/rtems/rtems_bsdnet.h b/cpukit/libnetworking/rtems/rtems_bsdnet.h
new file mode 100644
index 0000000000..6c40e73f10
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_bsdnet.h
@@ -0,0 +1,317 @@
+/**
+ * @file rtems/rtems_bsdnet.h
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef _RTEMS_BSDNET_H
+#define _RTEMS_BSDNET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+
+/*
+ * If this file is included from inside the Network Stack proper or
+ * a device driver, then __INSIDE_RTEMS_BSD_TCPIP_STACK__ should be
+ * defined. This triggers a number of internally used definitions.
+ */
+
+#if defined(__INSIDE_RTEMS_BSD_TCPIP_STACK__)
+#undef _KERNEL
+#undef INET
+#undef NFS
+#undef DIAGNOSTIC
+#undef BOOTP_COMPAT
+#undef __BSD_VISIBLE
+
+#define _KERNEL
+#define INET
+#define NFS
+#define DIAGNOSTIC
+#define BOOTP_COMPAT
+#define __BSD_VISIBLE 1
+#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 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)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTEMS_BSDNET_H */
diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h
new file mode 100644
index 0000000000..a22a22391c
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h
@@ -0,0 +1,205 @@
+/*
+ * Declarations to fit FreeBSD to RTEMS.
+ *
+ *******************************************************************
+ * WARNING *
+ * This file should *never* be included by any application program *
+ *******************************************************************
+ *
+ * $Id$
+ */
+
+#ifndef _RTEMS_RTEMS_BSDNET_INTERNAL_H
+#define _RTEMS_RTEMS_BSDNET_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+
+typedef unsigned int vm_offset_t;
+typedef long long vm_ooffset_t;
+typedef unsigned int vm_pindex_t;
+typedef unsigned int vm_size_t;
+
+#ifndef __ioctl_command_defined
+typedef u_int32_t ioctl_command_t;
+#define __ioctl_command_defined
+#endif
+
+
+#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 <rtems/bsd/sys/cdefs.h>
+
+#include <sys/time.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; } 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
+
+void microtime (struct timeval *tv);
+#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
+struct sigaltstack {
+ char *ss_sp; /* signal stack base */
+ int ss_size; /* signal stack length */
+ int ss_flags; /* SS_DISABLE and/or SS_ONSTACK */
+};
+
+#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
+
+#include <rtems/endian.h>
+
+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_schednetisr (int n);
+int rtems_bsdnet_parse_driver_name (const struct rtems_bsdnet_ifconfig *config, char **namep);
+
+unsigned long rtems_bsdnet_seconds_since_boot (void);
+unsigned long rtems_bsdnet_random (void);
+
+rtems_id rtems_bsdnet_newproc (
+ char *name,
+ int stacksize,
+ void (*entry)(void *),
+ void *arg
+);
+
+rtems_status_code rtems_bsdnet_event_receive (
+ rtems_event_set event_in,
+ rtems_option option_set,
+ rtems_interval ticks,
+ rtems_event_set *event_out
+);
+
+/*
+ * 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 (char *name, size_t namelen);
+void domaininit (void *);
+void ifinit (void *);
+void ipintr (void);
+void arpintr (void);
+bool bootpc_init(bool, bool);
+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_24
+#define SOSLEEP_EVENT RTEMS_EVENT_25
+#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)
+# error "Network event conflict"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTEMS_RTEMS_BSDNET_INTERNAL_H */
diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet_malloc_starvation.c b/cpukit/libnetworking/rtems/rtems_bsdnet_malloc_starvation.c
new file mode 100644
index 0000000000..5e7d45d713
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_bsdnet_malloc_starvation.c
@@ -0,0 +1,19 @@
+/*
+ * Routine called when malloc() is not succeeding. This can be overridden
+ * by a BSP.
+ *
+ * $Id*
+ */
+
+#if 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/cpukit/libnetworking/rtems/rtems_dhcp.c b/cpukit/libnetworking/rtems/rtems_dhcp.c
new file mode 100644
index 0000000000..82f8fd9c5b
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_dhcp.c
@@ -0,0 +1,1231 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * WARNING:
+ * This file should be moved into c/src/libnetworking/nfs
+ * and the following two #ifndef...#endif blocks and the #undefs at
+ * the end of the file should be removed
+ */
+
+#ifndef __INSIDE_RTEMS_BSD_TCPIP_STACK__
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+#endif
+
+#ifndef __BSD_VISIBLE
+#define __BSD_VISIBLE 1
+#endif
+
+#if 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 <sys/ioctl.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"
+
+#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];
+};
+
+/*
+ * External Declarations for Functions found in
+ * rtems/c/src/libnetworking/nfs/
+ */
+extern int bootpc_call (struct dhcp_packet *call,
+ struct dhcp_packet *reply,
+ struct proc *procp);
+extern int bootpc_fakeup_interface (struct ifreq *ireq,
+ struct socket *so,
+ struct proc *procp);
+extern 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);
+extern void *bootp_strdup_realloc (char *dst,
+ const char *src);
+
+/*
+ * 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 };
+
+/*
+ * Format an IP address in dotted decimal.
+ */
+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_bsdnet_nameserver_count <
+ sizeof rtems_bsdnet_config.name_server /
+ sizeof rtems_bsdnet_config.name_server[0]))
+ {
+ 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)
+ {
+ dhcp_hostname = realloc (dhcp_hostname, len);
+ strncpy (dhcp_hostname, p, len);
+ }
+ else
+ 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;
+
+ /*
+ * 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;
+ int disconnected;
+ rtems_status_code ev_st;
+
+ sdl = (struct sockaddr_dl *) _sdl;
+
+ count = dhcp_elapsed_time;
+ disconnected = 0;
+
+ while (true)
+ {
+ /*
+ * Sleep until the next poll
+ */
+ timeout = TOD_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 (&call, &dhcp_req, procp);
+ 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;
+ }
+
+ 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_delete( RTEMS_SELF);
+
+}
+
+/*
+ * 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
+ */
+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 len;
+ int error;
+ struct sockaddr_in myaddr;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl = NULL;
+ struct proc *procp = NULL;
+
+ /*
+ * 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
+ */
+ len = dhcp_discover_req (&call, sdl, &xid);
+
+ /*
+ * Send the Discover.
+ */
+ error = bootpc_call (&call, &reply, procp);
+ 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;
+ }
+
+ /*
+ * Send a DHCP REQUEST
+ */
+ dhcp_request_req (&call, &reply, sdl, true);
+
+ error = bootpc_call (&call, &reply, procp);
+ 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++) {
+ strcpy(buf, "nameserver ");
+ strcat(buf, inet_ntoa(rtems_bsdnet_ntpserver[i]));
+ 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(TOD_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/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c
new file mode 100644
index 0000000000..609a19eb0a
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.c
@@ -0,0 +1,372 @@
+/*
+ $Id$
+
+ 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.com/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>
+
+struct proc; /* Unused parameter of some functions. */
+#include <sys/ioctl.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 */
+#include <arpa/inet.h> /* for inet_addr, inet_ntop */
+
+
+#define NETWORK_FAIL_TIMEOUT 5 /* the number of seconds before the interface is considered disconnected */
+#define NETWORK_DOWN_TIME 30 /* number of seconds the interface remains down */
+#define BROADCAST_DELAY 0 /* Delay (seconds) before broadcasts are sent */
+#define DHCP_MONITOR_PRIORITY 250 /* Low 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;
+}
+
+
+#if NETWORK_DOWN_TIME
+static int
+dhcp_if_down (const char* ifname)
+{
+ int 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;
+}
+#endif
+
+static int
+dhcp_if_up (const char* ifname)
+{
+ int 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)
+{
+ short 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(TOD_MILLISECONDS_TO_TICKS(BROADCAST_DELAY * 1000));
+#endif
+
+ 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;
+ int 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;
+#if NETWORK_DOWN_TIME
+ dhcp_if_down(ifname);
+ rtems_task_wake_after(TOD_MILLISECONDS_TO_TICKS(NETWORK_DOWN_TIME * 1000));
+ dhcp_if_up(ifname);
+ downcount = 0;
+#endif
+ }
+ }
+ }
+
+ rtems_task_wake_after(TOD_MILLISECONDS_TO_TICKS(1000));
+ }
+
+error_out:
+ printf("Stopping dhcp monitoring application.\n");
+ rtems_task_delete(RTEMS_SELF);
+}
+
+/*
+* 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;
+ int 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);
+ }
+#endif
+}
+
diff --git a/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h
new file mode 100644
index 0000000000..320f9bf151
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_dhcp_failsafe.h
@@ -0,0 +1,29 @@
+/*
+ $Id$
+
+ 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.com/license/LICENSE.
+*/
+
+#ifndef _RTEMS_DHCP_FAILSAFE_H_
+#define _RTEMS_DHCP_FAILSAFE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void rtems_bsdnet_do_dhcp_failsafe (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c
new file mode 100644
index 0000000000..088479cfb8
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_glue.c
@@ -0,0 +1,1310 @@
+/*
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define RTEMS_FAST_MUTEX
+
+#ifdef RTEMS_FAST_MUTEX
+#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
+#endif
+
+#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/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/ioctl.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <vm/vm.h>
+#include <arpa/inet.h>
+
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include "loop.h"
+
+/*
+ * Sysctl init all.
+ */
+void sysctl_register_all(void *arg);
+
+/*
+ * Memory allocation
+ */
+static uint32_t nmbuf = (64L * 1024L) / MSIZE;
+ uint32_t nmbclusters = (128L * 1024L) / MCLBYTES;
+
+/*
+ * Network task synchronization
+ */
+static rtems_id networkSemaphore;
+#ifdef RTEMS_FAST_MUTEX
+Semaphore_Control *the_networkSemaphore;
+#endif
+static rtems_id networkDaemonTid;
+static uint32_t networkDaemonPriority;
+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));
+}
+
+/*
+ * 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 (;;) {
+ p = malloc (size);
+ if (p || (flags & M_NOWAIT))
+ return p;
+ rtems_bsdnet_semaphore_release ();
+ if (++try >= 30) {
+ rtems_bsdnet_malloc_starvation();
+ try = 0;
+ }
+ rtems_task_wake_after (rtems_bsdnet_ticks_per_second);
+ rtems_bsdnet_semaphore_obtain ();
+ }
+}
+
+/*
+ * 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 * MSIZE + MSIZE - 1,MBUF_MALLOC_MBUF);
+ p = (char *)(((uintptr_t)p + MSIZE - 1) & ~(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 += 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;
+}
+
+/*
+ * RTEMS Specific Helper Routines
+ */
+extern void rtems_set_udp_buffer_sizes( u_long, u_long );
+extern void rtems_set_tcp_buffer_sizes( u_long, u_long );
+extern void rtems_set_sb_efficiency( u_long );
+
+/*
+ * Initialize and start network operations
+ */
+static int
+rtems_bsdnet_initialize (void)
+{
+ rtems_status_code sc;
+
+ /*
+ * Set the priority of all network tasks
+ */
+ if (rtems_bsdnet_config.network_task_priority == 0)
+ networkDaemonPriority = 100;
+ else
+ networkDaemonPriority = rtems_bsdnet_config.network_task_priority;
+
+ /*
+ * Set the memory allocation limits
+ */
+ if (rtems_bsdnet_config.mbuf_bytecount)
+ nmbuf = rtems_bsdnet_config.mbuf_bytecount / 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 );
+
+ /*
+ * Create the task-synchronization semaphore
+ */
+ sc = rtems_semaphore_create (rtems_build_name('B', 'S', 'D', 'n'),
+ 0,
+ RTEMS_PRIORITY |
+ RTEMS_BINARY_SEMAPHORE |
+ RTEMS_INHERIT_PRIORITY |
+ RTEMS_NO_PRIORITY_CEILING |
+ RTEMS_LOCAL,
+ 0,
+ &networkSemaphore);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Can't create network seamphore: `%s'\n", rtems_status_text (sc));
+ return -1;
+ }
+#ifdef RTEMS_FAST_MUTEX
+ {
+ Objects_Locations location;
+ the_networkSemaphore = _Semaphore_Get( networkSemaphore, &location );
+ _Thread_Enable_dispatch();
+ }
+#endif
+
+ /*
+ * 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;
+
+ /*
+ * Ensure that `seconds' is greater than 0
+ */
+ while (rtems_bsdnet_seconds_since_boot() == 0)
+ rtems_task_wake_after(1);
+
+ /*
+ * Set up BSD-style sockets
+ */
+ if (bsd_init () < 0)
+ 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)
+{
+#ifdef RTEMS_FAST_MUTEX
+ ISR_Level level;
+ _ISR_Disable (level);
+ _CORE_mutex_Seize (
+ &the_networkSemaphore->Core_control.mutex,
+ networkSemaphore,
+ 1, /* wait */
+ 0, /* forever */
+ level
+ );
+ if (_Thread_Executing->Wait.return_code)
+ rtems_panic ("rtems-net: can't obtain network sema: %d\n",
+ _Thread_Executing->Wait.return_code);
+#else
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_obtain (networkSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_panic ("rtems-net: can't obtain network semaphore: `%s'\n",
+ rtems_status_text (sc));
+#endif
+}
+
+/*
+ * Release network mutex
+ */
+void
+rtems_bsdnet_semaphore_release (void)
+{
+#ifdef RTEMS_FAST_MUTEX
+ int i;
+
+ _Thread_Disable_dispatch();
+ i = _CORE_mutex_Surrender (
+ &the_networkSemaphore->Core_control.mutex,
+ networkSemaphore,
+ NULL
+ );
+ _Thread_Enable_dispatch();
+ if (i)
+ rtems_panic ("rtems-net: can't release network sema: %i\n");
+#else
+ rtems_status_code sc;
+
+ sc = rtems_semaphore_release (networkSemaphore);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_panic ("rtems-net: can't release network semaphore: `%s'\n",
+ rtems_status_text (sc));
+#endif
+}
+
+/*
+ * Wait for something to happen to a socket buffer
+ */
+int
+sbwait(struct sockbuf *sb)
+{
+ rtems_event_set events;
+ rtems_id tid;
+ rtems_status_code sc;
+
+ /*
+ * Soak up any pending events.
+ * The sleep/wakeup synchronization in the FreeBSD
+ * kernel has no memory.
+ */
+ rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
+
+ /*
+ * Set this task as the target of the wakeup operation.
+ */
+ rtems_task_ident (RTEMS_SELF, 0, &tid);
+ sb->sb_sel.si_pid = tid;
+
+ /*
+ * Show that socket is waiting
+ */
+ sb->sb_flags |= SB_WAIT;
+
+ /*
+ * Release the network semaphore.
+ */
+ rtems_bsdnet_semaphore_release ();
+
+ /*
+ * Wait for the wakeup event.
+ */
+ sc = rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, sb->sb_timeo, &events);
+
+ /*
+ * Reobtain the network semaphore.
+ */
+ rtems_bsdnet_semaphore_obtain ();
+
+ /*
+ * Return the status of the wait.
+ */
+ switch (sc) {
+ case RTEMS_SUCCESSFUL: return 0;
+ case RTEMS_TIMEOUT: return EWOULDBLOCK;
+ default: return ENXIO;
+ }
+}
+
+
+/*
+ * Wake up the task waiting on a socket buffer.
+ */
+void
+sowakeup(
+ struct socket *so,
+ struct sockbuf *sb)
+{
+ if (sb->sb_flags & SB_WAIT) {
+ sb->sb_flags &= ~SB_WAIT;
+ rtems_event_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)
+{
+ rtems_event_set events;
+ rtems_id tid;
+ rtems_status_code sc;
+
+ /*
+ * Soak up any pending events.
+ * The sleep/wakeup synchronization in the FreeBSD
+ * kernel has no memory.
+ */
+ rtems_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
+
+ /*
+ * Set this task as the target of the wakeup operation.
+ */
+ if (so->so_pgid)
+ rtems_panic ("Another task is already sleeping on that socket");
+ rtems_task_ident (RTEMS_SELF, 0, &tid);
+ so->so_pgid = tid;
+
+ /*
+ * Wait for the wakeup event.
+ */
+ sc = rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, so->so_rcv.sb_timeo, &events);
+
+ /*
+ * Relinquish ownership of the socket.
+ */
+ so->so_pgid = 0;
+
+ switch (sc) {
+ case RTEMS_SUCCESSFUL: return 0;
+ case RTEMS_TIMEOUT: return EWOULDBLOCK;
+ default: return ENXIO;
+ }
+}
+
+/*
+ * Wake up a task waiting for a connection/disconnection to complete.
+ */
+void
+soconnwakeup (struct socket *so)
+{
+ if (so->so_pgid)
+ rtems_event_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_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
+ */
+rtems_id
+rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
+{
+ 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),
+ 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));
+
+ /*
+ * 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_receive (event_in, option_set, ticks, event_out);
+ rtems_bsdnet_semaphore_obtain ();
+ return sc;
+}
+
+/*
+ * Return time since startup
+ */
+void
+microtime (struct timeval *t)
+{
+ rtems_interval now;
+
+ now = rtems_clock_get_ticks_since_boot();
+ t->tv_sec = now / rtems_bsdnet_ticks_per_second;
+ t->tv_usec = (now % rtems_bsdnet_ticks_per_second) * rtems_bsdnet_microseconds_per_tick;
+}
+
+unsigned long
+rtems_bsdnet_seconds_since_boot (void)
+{
+ rtems_interval now;
+
+ now = rtems_clock_get_ticks_since_boot();
+ return now / rtems_bsdnet_ticks_per_second;
+}
+
+/*
+ * 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
+ */
+u_int
+in_cksum_hdr (const void *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 (;;) {
+ rtems_bsdnet_semaphore_release ();
+ rtems_task_wake_after (1);
+ rtems_bsdnet_semaphore_obtain ();
+ 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 (;;) {
+ rtems_bsdnet_semaphore_release ();
+ rtems_task_wake_after (1);
+ rtems_bsdnet_semaphore_obtain ();
+ 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/cpukit/libnetworking/rtems/rtems_malloc_mbuf.c b/cpukit/libnetworking/rtems/rtems_malloc_mbuf.c
new file mode 100644
index 0000000000..a2bd34a4c4
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_malloc_mbuf.c
@@ -0,0 +1,39 @@
+/*
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define RTEMS_FAST_MUTEX
+
+#ifdef RTEMS_FAST_MUTEX
+#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
+#endif
+
+#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/cpukit/libnetworking/rtems/rtems_mii_ioctl.c b/cpukit/libnetworking/rtems/rtems_mii_ioctl.c
new file mode 100644
index 0000000000..93e9a0d580
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_mii_ioctl.c
@@ -0,0 +1,172 @@
+/* $Id$ */
+
+/* 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/cpukit/libnetworking/rtems/rtems_mii_ioctl.h b/cpukit/libnetworking/rtems/rtems_mii_ioctl.h
new file mode 100644
index 0000000000..160de34e92
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_mii_ioctl.h
@@ -0,0 +1,141 @@
+/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
+ * to be used by ethernet drivers [from their ioctl].
+ *
+ * NOTE: This much simpler than the BSD ifmedia API
+ *
+ * $Id$
+ */
+
+/*
+ * 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/cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c b/cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c
new file mode 100644
index 0000000000..c43f0d077b
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c
@@ -0,0 +1,259 @@
+/* $Id$ */
+
+/* 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/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/cpukit/libnetworking/rtems/rtems_select.c b/cpukit/libnetworking/rtems/rtems_select.c
new file mode 100644
index 0000000000..927c07daa6
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_select.c
@@ -0,0 +1,178 @@
+/*
+ * $Id$
+ */
+
+#if 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/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 *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *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 events;
+
+ 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_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
+ 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_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, timo, &events);
+ }
+
+#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/cpukit/libnetworking/rtems/rtems_showicmpstat.c b/cpukit/libnetworking/rtems/rtems_showicmpstat.c
new file mode 100644
index 0000000000..c554fa70a1
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_showicmpstat.c
@@ -0,0 +1,70 @@
+/*
+ * $Id$
+ */
+
+#if 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>
+
+/*
+ * 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/cpukit/libnetworking/rtems/rtems_showifstat.c b/cpukit/libnetworking/rtems/rtems_showifstat.c
new file mode 100644
index 0000000000..17722093fb
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_showifstat.c
@@ -0,0 +1,157 @@
+/*
+ * $Id$
+ */
+
+#if 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/ioctl.h>
+#include <sys/mbuf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <arpa/inet.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/cpukit/libnetworking/rtems/rtems_showipstat.c b/cpukit/libnetworking/rtems/rtems_showipstat.c
new file mode 100644
index 0000000000..75eabca2c1
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_showipstat.c
@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ */
+
+#if 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_var.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);
+ printf ("\n");
+}
diff --git a/cpukit/libnetworking/rtems/rtems_showmbuf.c b/cpukit/libnetworking/rtems/rtems_showmbuf.c
new file mode 100644
index 0000000000..a4404a5a6c
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_showmbuf.c
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ */
+
+#if 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>
+
+/*
+ * 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/cpukit/libnetworking/rtems/rtems_showroute.c b/cpukit/libnetworking/rtems/rtems_showroute.c
new file mode 100644
index 0000000000..e30c0eaccf
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_showroute.c
@@ -0,0 +1,240 @@
+/*
+ * $Id$
+ */
+
+#if 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_dl.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+/*
+ * We'll use the application versions of realloc and free.
+ */
+#undef free
+#undef malloc
+#include <stdlib.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/cpukit/libnetworking/rtems/rtems_showtcpstat.c b/cpukit/libnetworking/rtems/rtems_showtcpstat.c
new file mode 100644
index 0000000000..15612878ef
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_showtcpstat.c
@@ -0,0 +1,106 @@
+/*
+ * $Id$
+ */
+
+#if 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>
+
+/*
+ * 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/cpukit/libnetworking/rtems/rtems_showudpstat.c b/cpukit/libnetworking/rtems/rtems_showudpstat.c
new file mode 100644
index 0000000000..d47534d964
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_showudpstat.c
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ */
+
+#if 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>
+
+/*
+ * 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/cpukit/libnetworking/rtems/rtems_socketpair.c b/cpukit/libnetworking/rtems/rtems_socketpair.c
new file mode 100644
index 0000000000..09f93ad69a
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_socketpair.c
@@ -0,0 +1,51 @@
+/*
+ * 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.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <errno.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/cpukit/libnetworking/rtems/rtems_syscall.c b/cpukit/libnetworking/rtems/rtems_syscall.c
new file mode 100644
index 0000000000..ee2cf1728e
--- /dev/null
+++ b/cpukit/libnetworking/rtems/rtems_syscall.c
@@ -0,0 +1,782 @@
+/*
+ * $Id$
+ */
+
+#if 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/route.h>
+
+/*
+ * Since we are "in the kernel", these do not get prototyped in sys/socket.h
+ */
+ssize_t send(int, const void *, size_t, int);
+ssize_t recv(int, void *, size_t, int);
+
+/*
+ * Hooks to RTEMS I/O system
+ */
+static const rtems_filesystem_file_handlers_r socket_handlers;
+int rtems_bsdnet_makeFdForSocket(
+ void *so, const rtems_filesystem_file_handlers_r *h);
+struct socket *rtems_bsdnet_fdToSocket(int 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, &socket_handlers);
+ if (fd < 0)
+ soclose (so);
+ }
+ else {
+ errno = error;
+ fd = -1;
+ }
+ rtems_bsdnet_semaphore_release ();
+ return fd;
+}
+
+int
+bind (int s, struct sockaddr *name, int 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, struct sockaddr *name, int 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;
+ }
+ while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
+ error = soconnsleep (so);
+ if (error)
+ break;
+ }
+ if (error == 0) {
+ error = so->so_error;
+ so->so_error = 0;
+ }
+ bad:
+ 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, int *namelen)
+{
+ int fd;
+ struct socket *head, *so;
+ struct mbuf *nam;
+
+ 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;
+ }
+ while (head->so_comp.tqh_first == NULL && head->so_error == 0) {
+ if (head->so_state & SS_CANTRCVMORE) {
+ head->so_error = ECONNABORTED;
+ break;
+ }
+ head->so_error = soconnsleep (head);
+ }
+ if (head->so_error) {
+ errno = head->so_error;
+ head->so_error = 0;
+ 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, &socket_handlers);
+ 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, int 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, const struct sockaddr *from, int *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, int 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, int *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, int *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, int *namelen)
+{
+ return getpeersockname (s, name, namelen, 1);
+}
+int
+getsockname (int s, struct sockaddr *name, int *namelen)
+{
+ return getpeersockname (s, name, namelen, 0);
+}
+
+int
+sysctl(int *name, u_int namelen, void *oldp,
+ size_t *oldlenp, 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;
+ }
+ 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)
+{
+ switch (command) {
+ case FIONBIO:
+ if (*(int *)buffer) {
+ iop->flags |= O_NONBLOCK;
+ so->so_state |= SS_NBIO;
+ }
+ else {
+ iop->flags &= ~O_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, uint32_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 (int cmd, rtems_libio_t *iop)
+{
+ struct socket *so;
+
+ if (cmd == F_SETFL) {
+ rtems_bsdnet_semaphore_obtain ();
+ if ((so = iop->data1) == NULL) {
+ rtems_bsdnet_semaphore_release ();
+ return EBADF;
+ }
+ if (iop->flags & LIBIO_FLAGS_NO_DELAY)
+ so->so_state |= SS_NBIO;
+ else
+ so->so_state &= ~SS_NBIO;
+ rtems_bsdnet_semaphore_release ();
+ }
+ return 0;
+}
+
+static int
+rtems_bsdnet_fstat (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 = {
+ rtems_filesystem_default_open, /* open */
+ rtems_bsdnet_close, /* close */
+ rtems_bsdnet_read, /* read */
+ rtems_bsdnet_write, /* write */
+ rtems_bsdnet_ioctl, /* ioctl */
+ rtems_filesystem_default_lseek, /* lseek */
+ rtems_bsdnet_fstat, /* fstat */
+ rtems_filesystem_default_fchmod, /* fchmod */
+ rtems_filesystem_default_ftruncate, /* ftruncate */
+ rtems_filesystem_default_fpathconf, /* fpathconf */
+ rtems_filesystem_default_fsync, /* fsync */
+ rtems_filesystem_default_fdatasync, /* fdatasync */
+ rtems_bsdnet_fcntl, /* fcntl */
+ rtems_filesystem_default_rmnod /* rmnod */
+};
diff --git a/cpukit/libnetworking/rtems/sghostname.c b/cpukit/libnetworking/rtems/sghostname.c
new file mode 100644
index 0000000000..0303813e12
--- /dev/null
+++ b/cpukit/libnetworking/rtems/sghostname.c
@@ -0,0 +1,53 @@
+/*
+ * RTEMS versions of hostname functions
+ * FIXME: Not thread-safe
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <errno.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 (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;
+}
diff --git a/cpukit/libnetworking/rtems/tftp.h b/cpukit/libnetworking/rtems/tftp.h
new file mode 100644
index 0000000000..ae8588deca
--- /dev/null
+++ b/cpukit/libnetworking/rtems/tftp.h
@@ -0,0 +1,45 @@
+/*
+ * $Id$
+ */
+
+/*
+ * Trivial File Transfer Protocol (TFTP)
+ *
+ * Transfer file to/from remote host
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+/*
+ * Usage:
+ *
+ * To open `/bootfiles/image' on `hostname' for reading:
+ * fd = open ("/TFTP/hostname/bootfiles/image", O_RDONLY);
+ *
+ * The 'TFTP' is the mount path and the `hostname' must be four dot-separated
+ * decimal values.
+ */
+
+#ifndef _RTEMS_TFTP_H
+#define _RTEMS_TFTP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems/libio.h>
+
+/*
+ * Filesystem Mount table entry.
+ */
+int rtems_tftpfs_initialize(rtems_filesystem_mount_table_entry_t *temp_mt_entry);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif