diff options
Diffstat (limited to 'cpukit/libnetworking/rtems')
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 |