diff options
Diffstat (limited to 'cpukit/libnetworking/rtems')
-rw-r--r-- | cpukit/libnetworking/rtems/issetugid.c | 8 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_bootp.c | 15 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_bsdnet.h | 99 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_bsdnet_internal.h | 156 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_glue.c | 898 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_showicmpstat.c | 56 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_showifstat.c | 106 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_showipstat.c | 55 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_showmbuf.c | 61 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_showroute.c | 159 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_showtcpstat.c | 98 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_showudpstat.c | 44 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/rtems_syscall.c | 743 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/sghostname.c | 47 | ||||
-rw-r--r-- | cpukit/libnetworking/rtems/tftp.h | 85 |
15 files changed, 2630 insertions, 0 deletions
diff --git a/cpukit/libnetworking/rtems/issetugid.c b/cpukit/libnetworking/rtems/issetugid.c new file mode 100644 index 0000000000..1ae81c9f2e --- /dev/null +++ b/cpukit/libnetworking/rtems/issetugid.c @@ -0,0 +1,8 @@ +/* + * Dummy version of BSD routine + */ +int +issetugid (void) +{ + return 0; +} diff --git a/cpukit/libnetworking/rtems/rtems_bootp.c b/cpukit/libnetworking/rtems/rtems_bootp.c new file mode 100644 index 0000000000..c3bb8d7ad4 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_bootp.c @@ -0,0 +1,15 @@ +#include <rtems.h> +#include <rtems/error.h> +#include <sys/types.h> +#include <rtems/rtems_bsdnet.h> + +/* + * Perform a BOOTP request + */ +void +rtems_bsdnet_do_bootp (void) +{ + rtems_bsdnet_semaphore_obtain (); + bootpc_init (); + rtems_bsdnet_semaphore_release (); +} diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet.h b/cpukit/libnetworking/rtems/rtems_bsdnet.h new file mode 100644 index 0000000000..9ae48d8cfe --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_bsdnet.h @@ -0,0 +1,99 @@ +#ifndef _RTEMS_BSDNET_ +#define _RTEMS_BSDNET_ + +#include <rtems.h> + +/* + * Values that may be obtained by BOOTP + */ +extern struct in_addr rtems_bsdnet_bootp_server_address; +extern char *rtems_bsdnet_bootp_boot_file_name; + +/* + * 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 two entries must be supplied for each interface. + */ + char *name; + int (*attach)(struct rtems_bsdnet_ifconfig *conf); + + /* + * 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; +}; + +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 */ +}; +extern struct rtems_bsdnet_config rtems_bsdnet_config; +int rtems_bsdnet_initialize_network (void); +void rtems_bsdnet_do_bootp (void); + +#endif /* _RTEMS_BSDNET_ */ diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h new file mode 100644 index 0000000000..f27eb74491 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h @@ -0,0 +1,156 @@ +/* + * Declarations to fit FreeBSD to RTEMS. + * This include file should *never* be exposed to the application programmer. + */ + +#ifndef _RTEMS_BSDNET_INTERNAL_H_ +#define _RTEMS_BSDNET_INTERNAL_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; + +#define _BSD_OFF_T_ rtems_signed32 +#define _BSD_PID_T_ rtems_id +#define _BSD_VA_LIST_ char * + +#include <sys/time.h> +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +}; +struct mdproc { + int md_flags; + int *md_regs; +}; + +#define USHRT_MAX 65535 + +/* + * Other RTEMS/BSD glue + */ +struct socket; +extern void soconnsleep (struct socket *so); +extern void soconnwakeup (struct socket *so); +#define splnet() 0 +#define splimp() 0 +#define splx(s) + +#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 SHRT_MAX 65535 + +#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.... + */ +#include <sys/cdefs.h> + +typedef u_int64_t u_quad_t; /* quads */ +typedef int64_t quad_t; +typedef quad_t * qaddr_t; + +typedef void __sighandler_t __P((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; +typedef struct vm_page *vm_page_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 <machine/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 file; +struct buf; +struct tty; +struct uio; + +/* + * Redo kernel memory allocation + */ +#define malloc rtems_bsdnet_malloc +#define free rtems_bsdnet_free + +#define M_NOWAIT 0x0001 +void *rtems_bsdnet_malloc (unsigned long 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); + +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; +extern struct in_addr rtems_bsdnet_nameserver[]; +extern int rtems_bsdnet_nameserver_count; + +/* + * Internal IOCTL command + */ +#define SIO_RTEMS_SHOW_STATS _IO('i', 250) + +#endif /* _RTEMS_BSDNET_INTERNAL_H_ */ diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c new file mode 100644 index 0000000000..339d99052b --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -0,0 +1,898 @@ +#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 <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> + +/* + * 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 (1 << NETISR_IP) +#define NETISR_ARP_EVENT (1 << NETISR_ARP) +#define NETISR_EVENTS (NETISR_IP_EVENT|NETISR_ARP_EVENT) + + +/* + * Memory allocation + */ +static int nmbuf = (64 * 1024) / MSIZE; + int nmbclusters = (128 * 1024) / MCLBYTES; + +/* + * Socket buffering parameters + */ +unsigned long sb_efficiency = 8; + +/* + * Network task synchronization + */ +static rtems_id networkSemaphore; +static rtems_id networkDaemonTid; +static rtems_unsigned32 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; +static struct callout *callfree, calltodo; + +/* + * FreeBSD variables + */ +int nfs_diskless_valid; + +/* + * BOOTP values + */ +struct in_addr rtems_bsdnet_log_host_address; +struct in_addr rtems_bsdnet_bootp_server_address; +char *rtems_bsdnet_bootp_boot_file_name; +char *rtems_bsdnet_domain_name; +struct in_addr rtems_bsdnet_nameserver[sizeof rtems_bsdnet_config.name_server / + sizeof rtems_bsdnet_config.name_server[0]]; +int rtems_bsdnet_nameserver_count; + +extern rtems_libio_handler_t rtems_bsdnet_io_handler; + +/* + * 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 (unsigned long size, int type, int flags) +{ + void *p; + + for (;;) { + p = malloc (size); + if (p) + return p; + if (flags & M_NOWAIT) + return p; + /* + * FIXME: This should be redone as: + * static volatile int rtems_bsdnet_need_memory; + * + * rtems_bsdnet_need_memory = 1; + * message_queue_receive + * + * Then in rtems_bsdnet_freee: + * free (....); + * if (rtems_bsdnet_need_memory) + * rtems_bsdnet_need_memory = 0; + * message_queue_broadcast + */ + rtems_task_wake_after (rtems_bsdnet_ticks_per_second); + } +} + +/* + * Free FreeBSD memory + * FIXME: This should be modified to keep memory allocation statistics. + */ +void +rtems_bsdnet_free (void *addr, int type) +{ + free (addr); +} + +/* + * Do the initializations required by the BSD code + * FIXME: Maybe we should use a different memory allocation scheme that + * would let us share space between mbufs and mbuf clusters. + * For now, we'll just take the easy way out! + */ +static void +bsd_init () +{ + /* + * Set up mbuf data strutures + * Cluster allocation *must* come first -- see comment on kmem_malloc(). + */ + m_clalloc (nmbclusters, M_DONTWAIT); + mclrefcnt = malloc (nmbclusters); + if (mclrefcnt == NULL) + rtems_panic ("No memory for mbuf cluster reference counts."); + memset (mclrefcnt, '\0', nmbclusters); + m_mballoc (nmbuf, M_DONTWAIT); + mbstat.m_mtypes[MT_FREE] = nmbuf; + + + /* + * Set up domains + */ + { + extern struct domain routedomain; + extern struct domain inetdomain; + + routedomain.dom_next = domains; + domains = &routedomain; + inetdomain.dom_next = domains; + domains = &inetdomain; + domaininit (NULL); + } + + /* + * Set up interfaces + */ + ifinit (NULL); +} + +/* + * Initialize and start network operations + */ +static void +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; + + /* + * Create the task-synchronization semaphore + */ + sc = rtems_semaphore_create (rtems_build_name('B', 'S', 'D', 'n'), + 0, + RTEMS_FIFO | + RTEMS_BINARY_SEMAPHORE | + RTEMS_NO_INHERIT_PRIORITY | + RTEMS_NO_PRIORITY_CEILING | + RTEMS_LOCAL, + 0, + &networkSemaphore); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't create network seamphore: `%s'\n", rtems_status_text (sc)); + + /* + * Compute clock tick conversion factors + */ + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &rtems_bsdnet_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 + */ + rtems_task_wake_after (rtems_bsdnet_ticks_per_second); + + /* + * Set up BSD-style sockets + */ + bsd_init (); + + /* + * Start network daemon + */ + networkDaemonTid = rtems_bsdnet_newproc ("ntwk", 4096, networkDaemon, NULL); + + /* + * Register as an external I/O handler + */ + rtems_register_libio_handler (RTEMS_FILE_DESCRIPTOR_TYPE_SOCKET, + &rtems_bsdnet_io_handler); + + /* + * Let other network tasks begin + */ + rtems_bsdnet_semaphore_release (); +} + +rtems_id TaskWithSemaphore; +/* + * Obtain network mutex + */ +void +rtems_bsdnet_semaphore_obtain (void) +{ + rtems_status_code sc; + + sc = rtems_semaphore_obtain (networkSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT); +rtems_task_ident (RTEMS_SELF, 0, &TaskWithSemaphore); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't obtain network semaphore: `%s'\n", rtems_status_text (sc)); +} + +/* + * Release network mutex + */ +void +rtems_bsdnet_semaphore_release (void) +{ + rtems_status_code sc; + +TaskWithSemaphore = 0; + sc = rtems_semaphore_release (networkSemaphore); + if (sc != RTEMS_SUCCESSFUL) + rtems_panic ("Can't release network semaphore: `%s'\n", rtems_status_text (sc)); + } + +/* + * Wait for something to happen to a socket buffer + */ +int +sbwait(sb) + 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. + */ + if (sb->sb_sel.si_pid) + rtems_panic ("Another task is already sleeping on that socket buffer"); + rtems_task_ident (RTEMS_SELF, 0, &tid); + sb->sb_sel.si_pid = tid; + + /* + * Mark the socket buffer as 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 (); + + /* + * Relinquish ownership of the socket buffer + */ + sb->sb_flags &= ~SB_WAIT; + sb->sb_sel.si_pid = 0; + + /* + * 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(so, sb) + register struct socket *so; + register struct sockbuf *sb; +{ + if (sb->sb_flags & SB_WAIT) { + sb->sb_flags &= ~SB_WAIT; + rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT); + } +} + +/* + * For now, a socket can be used by only one task at a time. + */ +int +sb_lock(sb) + register 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. + */ +void +soconnsleep (struct socket *so) +{ + rtems_event_set events; + rtems_id tid; + + /* + * 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. + */ + rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Relinquish ownership of the socket. + */ + so->so_pgid = 0; +} + +/* + * 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_event_set events; + rtems_interval now; + int ticksPassed; + unsigned32 timeout; + struct callout *c; + + for (;;) { + c = calltodo.c_next; + if (c) + timeout = c->c_time; + else + timeout = RTEMS_NO_TIMEOUT; + rtems_bsdnet_event_receive (NETISR_EVENTS, + RTEMS_EVENT_ANY | RTEMS_WAIT, + timeout, + &events); + if (events & NETISR_IP_EVENT) + ipintr (); + if (events & NETISR_ARP_EVENT) + arpintr (); + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + 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; + + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + 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; + + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + return now / rtems_bsdnet_ticks_per_second; +} + +/* + * Fake random number generator + */ +unsigned long +rtems_bsdnet_random (void) +{ + rtems_interval now; + + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + return (now * 99991); +} + +/* + * Callout list processing + */ +void +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 + * FIXME: 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); + } +} + +/* + * Hack alert: kmem_malloc `knows' that its + * first invocation is to get mbuf clusters! + */ +int mb_map_full; +vm_map_t mb_map; +vm_offset_t +kmem_malloc (vm_map_t *map, vm_size_t size, boolean_t waitflag) +{ + void *p; + + /* + * Can't get memory if we're already running. + */ + if (networkDaemonTid) { + if (waitflag == M_WAITOK) + rtems_panic ("Someone is asking for more memory"); + return 0; + } + +#define ROUNDSIZE 2048 + p = malloc (size+ROUNDSIZE); + p = (void *)((unsigned long)p & ~(ROUNDSIZE-1)); + if ((p == NULL) && (waitflag == M_WAITOK)) + rtems_panic ("Can't get initial network memory!"); + if (mbutl == NULL) + mbutl = p; + return (vm_offset_t)p; +} + +/* + * IP header checksum routine for processors which don't have an inline version + */ +u_int +in_cksum_hdr (const void *ip) +{ + rtems_unsigned32 sum; + const rtems_unsigned16 *sp; + int i; + + sum = 0; + sp = (rtems_unsigned16 *)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 void +rtems_bsdnet_setup (void) +{ + struct rtems_bsdnet_ifconfig *ifp; + int s; + struct ifreq ifreq; + struct sockaddr_in address; + struct sockaddr_in netmask; + struct sockaddr_in broadcast; + struct sockaddr_in gateway; + int i; + + /* + * 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]); + } + + /* + * Configure interfaces + */ + s = socket (AF_INET, SOCK_DGRAM, 0); + if (s < 0) + rtems_panic ("Can't create initial socket: %s", strerror (errno)); + for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) { + if (ifp->ip_address == NULL) + continue; + + /* + * Get the interface flags + */ + strcpy (ifreq.ifr_name, ifp->name); + if (ioctl (s, SIOCGIFFLAGS, &ifreq) < 0) + rtems_panic ("Can't get %s flags: %s", ifp->name, strerror (errno)); + + /* + * Bring interface up + */ + ifreq.ifr_flags |= IFF_UP; + if (ioctl (s, SIOCSIFFLAGS, &ifreq) < 0) + rtems_panic ("Can't bring %s up: %s", ifp->name, strerror (errno)); + + /* + * 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); + memcpy (&ifreq.ifr_addr, &netmask, sizeof netmask); + if (ioctl (s, SIOCSIFNETMASK, &ifreq) < 0) + rtems_panic ("Can't set %s netmask: %s", ifp->name, strerror (errno)); + + /* + * 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); + memcpy (&ifreq.ifr_addr, &address, sizeof address); + if (ioctl (s, SIOCSIFADDR, &ifreq) < 0) + rtems_panic ("Can't set %s address: %s", ifp->name, strerror (errno)); + + /* + * Set interface broadcast address + */ + 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; + memcpy (&ifreq.ifr_broadaddr, &broadcast, sizeof broadcast); + if (ioctl (s, SIOCSIFBRDADDR, &ifreq) < 0) + rtems_panic ("Can't set %s broadcast address: %s", ifp->name, strerror (errno)); + } + + /* + * We're done with the dummy socket + */ + close (s); + + /* + * 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) + rtems_panic ("Can't set default route: %s", strerror (errno)); + } +} + +/* + * Initialize the network + */ +int +rtems_bsdnet_initialize_network (void) +{ + struct rtems_bsdnet_ifconfig *ifp; + + /* + * Start network tasks. + * Initialize BSD network data structures. + */ + rtems_bsdnet_initialize (); + + /* + * Attach interfaces + */ + for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) { + rtems_bsdnet_semaphore_obtain (); + (ifp->attach)(ifp); + rtems_bsdnet_semaphore_release (); + } + + /* + * Bring up the network + */ + rtems_bsdnet_setup (); + if (rtems_bsdnet_config.bootp) + (*rtems_bsdnet_config.bootp)(); + return 0; +} diff --git a/cpukit/libnetworking/rtems/rtems_showicmpstat.c b/cpukit/libnetworking/rtems/rtems_showicmpstat.c new file mode 100644 index 0000000000..0432c3a9a9 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showicmpstat.c @@ -0,0 +1,56 @@ +#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); +} + +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 ("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]); + } + } + + printf ("\n"); +} diff --git a/cpukit/libnetworking/rtems/rtems_showifstat.c b/cpukit/libnetworking/rtems/rtems_showifstat.c new file mode 100644 index 0000000000..b9a264fb34 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showifstat.c @@ -0,0 +1,106 @@ +#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 <net/if.h> +#include <netinet/in.h> + +/* + * Display an address + */ +static int +showaddress (char *name, struct sockaddr *a) +{ + struct sockaddr_in *sa; + + if (!a || (a->sa_family != AF_INET)) + return 0; + printf ("%s:", name); + sa = (struct sockaddr_in *)a; + printf ("%-16s", inet_ntoa (sa->sin_addr)); + return 1; +} + +/* + * Display interface statistics + */ +void +rtems_bsdnet_show_if_stats (void) +{ + struct ifnet *ifp; + struct ifaddr *ifa; + unsigned int bit, flags; + int printed; + + 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) { + 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"); + } + + printf ("Flags:"); + for (bit = 1, flags = ifp->if_flags ; flags ; bit <<= 1) { + char *cp; + switch (flags & bit) { + default: 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; + } + 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..053c07c8e7 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showipstat.c @@ -0,0 +1,55 @@ +#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..41c7f4c6a1 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showmbuf.c @@ -0,0 +1,61 @@ +#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..8695680d5e --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showroute.c @@ -0,0 +1,159 @@ +#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/route.h> + +#include <netinet/in.h> + +/* + * We'll use the application versions of malloc and free. + */ +#undef malloc +#undef free +/* + * Information per route + */ +struct rinfo { + struct in_addr dst; + struct in_addr gw_mask; + 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; +}; + +/* + * Package everything up before printing it. + * We don't want to block all network operations till + * the printing completes! + */ +static int +show_inet_route (rn, vw) + 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 + */ + r->dst = ((struct sockaddr_in *)rt_key(rt))->sin_addr; + if (rt->rt_flags & RTF_GATEWAY) + r->gw_mask = ((struct sockaddr_in *)rt->rt_gateway)->sin_addr; + else if (!(rt->rt_flags & RTF_HOST)) + r->gw_mask = ((struct sockaddr_in *)rt_mask(rt))->sin_addr; + 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, sizeof r->ifname); + r->ifunit = ifp->if_unit; + return 0; +} + +/* + * Reentrant version of inet_ntoa + */ +char * +inet_ntoa_r (struct in_addr ina, char *buf) +{ + unsigned char *ucp = (unsigned char *)&ina; + + sprintf (buf, "%d.%d.%d.%d", + ucp[0] & 0xff, + ucp[1] & 0xff, + ucp[2] & 0xff, + ucp[3] & 0xff); + return buf; +} + +void +rtems_bsdnet_show_inet_routes (void) +{ + struct radix_node_head *rnh; + struct dinfo d; + struct rinfo *r; + int i, error; + + 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 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]; + unsigned long flagbit; + + if (r->dst.s_addr == INADDR_ANY) + cp = "default"; + else + cp = inet_ntoa_r (r->dst, buf); + printf ("%-16s", cp); + if (!(r->flags & RTF_HOST)) + cp = inet_ntoa_r (r->gw_mask, buf); + else + cp = ""; + printf ("%-16s", cp); + 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..f293289df8 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showtcpstat.c @@ -0,0 +1,98 @@ +#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..a8d8dc2668 --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_showudpstat.c @@ -0,0 +1,44 @@ +#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_syscall.c b/cpukit/libnetworking/rtems/rtems_syscall.c new file mode 100644 index 0000000000..42361d22cd --- /dev/null +++ b/cpukit/libnetworking/rtems/rtems_syscall.c @@ -0,0 +1,743 @@ +#include <string.h> +#include <stdarg.h> +#include <stdio.h> + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/error.h> +#include <rtems/rtems_bsdnet.h> + +#include <sys/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/filio.h> + +#include <net/if.h> +#include <net/route.h> + +/* + ********************************************************************* + * Map RTEMS file descriptor to BSD socket * + ********************************************************************* + */ +struct fdsock { + int indexFreeNext; + struct socket *sock; +}; +static struct fdsock *fdsock; +static int fdsockCount; +static int indexFreeHead = -1; + +/* + * Convert an RTEMS file descriptor to a BSD socket pointer. + */ +static struct socket * +fdToSocket (int fd) +{ + int i; + struct socket *s; + + if ((fd < 0) + || (rtems_file_descriptor_type(fd) != RTEMS_FILE_DESCRIPTOR_TYPE_SOCKET) + || ((i = rtems_file_descriptor_base(fd)) >= fdsockCount) + || ((s = fdsock[i].sock) == NULL)) { + errno = EBADF; + return NULL; + } + return s; +} + +/* + * Enlarge the size of the file-descritor/socket pointer map. + */ +static int +enlargeFdMap (void) +{ + struct fdsock *nfdsock; + int i; + + nfdsock = realloc (fdsock, sizeof *fdsock * (fdsockCount + 20)); + if (nfdsock == NULL) { + errno = ENFILE; + return 0; + } + fdsock = nfdsock; + for (i = fdsockCount, fdsockCount += 20 ; i < fdsockCount ; i++) { + fdsock[i].sock = NULL; + fdsock[i].indexFreeNext = indexFreeHead; + indexFreeHead = i; + } + return 1; +} + +/* + * Create a file descriptor for a new socket + */ +static int +makeFd (struct socket *s) +{ + int i; + + if ((indexFreeHead < 0) && !enlargeFdMap ()) + return -1; + i = indexFreeHead; + indexFreeHead = fdsock[i].indexFreeNext; + fdsock[i].sock = s; + return rtems_make_file_descriptor(i,RTEMS_FILE_DESCRIPTOR_TYPE_SOCKET); +} + +/* + * 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 = -1; + int error; + struct socket *so; + + rtems_bsdnet_semaphore_obtain (); + error = socreate(domain, &so, type, protocol, NULL); + if (error == 0) { + fd = makeFd (so); + 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 = 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 = 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) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + 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) { + soconnsleep (so); + } + if (error == 0) { + error = so->so_error; + so->so_error = 0; + } + so->so_state &= ~SS_ISCONNECTING; + m_freem (nam); + if (error == 0) + 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 = 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 = 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; + } + 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 = makeFd (so); + if (fd < 0) { + TAILQ_INSERT_HEAD(&head->so_comp, so, so_list); + head->so_qlen++; + soconnwakeup (head); + rtems_bsdnet_semaphore_release (); + return -1; + } + so->so_state &= ~SS_COMP; + so->so_head = NULL; + + nam = m_get(M_WAIT, MT_SONAME); + (void) soaccept(so, nam); + if (name) { + /* check length before it is destroyed */ + if (*namelen > nam->m_len) + *namelen = nam->m_len; + memcpy (name, mtod(nam, caddr_t), *namelen); + } + m_freem(nam); + rtems_bsdnet_semaphore_release (); + return (fd); + +} + +/* + * 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, *control; + int i; + int len; + + rtems_bsdnet_semaphore_obtain (); + if ((so = 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); +} + +/* + * Send a message to a connected host + */ +ssize_t +send (int s, const void *buf, size_t buflen, int flags) +{ + return sendto (s, buf, buflen, flags, NULL, 0); +} + +/* + * 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 = 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; + caddr_t ctlbuf; + + len = mp->msg_controllen; + m = control; + mp->msg_controllen = 0; + ctlbuf = (caddr_t) 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; + msg.msg_namelen = *fromlen; + 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; +} + +/* + * Receive a message from a connected host + */ +ssize_t +recv (int s, void *buf, size_t buflen, int flags) +{ + return recvfrom (s, buf, buflen, flags, NULL, NULL); +} + +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 = 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 = 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; +} + +int +getpeername (int s, struct sockaddr *name, int *namelen) +{ + struct socket *so; + struct mbuf *m; + int len = *namelen; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = 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; + } + error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m); + if (error) { + 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; +} + +/* + ************************************************************************ + * RTEMS EXTERNAL I/O HANDLER ROUTINES * + ************************************************************************ + */ +static int +rtems_bsdnet_close (int fd) +{ + struct socket *so; + int error; + int i; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (fd)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + error = soclose (so); + i = rtems_file_descriptor_base(fd); + fdsock[i].indexFreeNext = indexFreeHead;; + indexFreeHead = i; + if (error) { + errno = error; + rtems_bsdnet_semaphore_release (); + return -1; + } + rtems_bsdnet_semaphore_release (); + return 0; +} + +static int +rtems_bsdnet_read (int fd, void *buffer, unsigned32 count) +{ + return recv (fd, buffer, count, 0); +} + +static int +rtems_bsdnet_write (int fd, const void *buffer, unsigned32 count) +{ + return send (fd, buffer, count, 0); +} + +static int +so_ioctl (struct socket *so, unsigned32 command, void *buffer) +{ + switch (command) { + case FIONBIO: + if (*(int *)buffer) + so->so_state |= SS_NBIO; + else + 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 (int fd, unsigned32 command, void *buffer) +{ + struct socket *so; + int error; + + rtems_bsdnet_semaphore_obtain (); + if ((so = fdToSocket (fd)) == NULL) { + rtems_bsdnet_semaphore_release (); + return -1; + } + error = so_ioctl (so, command, buffer); + rtems_bsdnet_semaphore_release (); + if (error) { + errno = error; + return -1; + } + return 0; +} + +rtems_libio_handler_t rtems_bsdnet_io_handler = { + NULL, /* open */ + rtems_bsdnet_close, /* close */ + rtems_bsdnet_read, /* read */ + rtems_bsdnet_write, /* write */ + rtems_bsdnet_ioctl, /* ioctl */ + NULL, /* lseek */ +}; + diff --git a/cpukit/libnetworking/rtems/sghostname.c b/cpukit/libnetworking/rtems/sghostname.c new file mode 100644 index 0000000000..ec9753649b --- /dev/null +++ b/cpukit/libnetworking/rtems/sghostname.c @@ -0,0 +1,47 @@ +/* + * RTEMS versions of hostname functions + * FIXME: Not thread-safe + */ + +#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, int namelen) +{ + char *cp = rtems_hostname; + + if (cp == NULL) + cp = ""; + strncpy (name, cp, namelen); + return 0; +} + +int +sethostname (char *name, int 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..d09782e22b --- /dev/null +++ b/cpukit/libnetworking/rtems/tftp.h @@ -0,0 +1,85 @@ +/* + * $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 `hostname' must be four dot-separated decimal values. + * + * To open a file on the host which supplied the BOOTP + * information just leave the `hostname' part empty: + * fd = open ("/TFTP//bootfiles/image", O_RDONLY); + * + */ + +#ifndef _TFTP_DRIVER_h +#define _TFTP_DRIVER_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Driver entry points + */ +#define TFTP_DRIVER_TABLE_ENTRY \ + { rtems_tftp_initialize, rtems_tftp_open, rtems_tftp_close, \ + rtems_tftp_read, rtems_tftp_write, rtems_tftp_control } + +rtems_device_driver rtems_tftp_initialize( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_open( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_close( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_read( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_write( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +rtems_device_driver rtems_tftp_control( + rtems_device_major_number, + rtems_device_minor_number, + void * +); + +#ifdef __cplusplus +} +#endif + +#endif |