From db9a26cbd125ec106e040ea6084911f9bc0c0198 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 4 Feb 2000 06:32:39 +0000 Subject: 2000-02-03 Roland McGrath Complete overhaul of pfinet based on the IPv4 networking code from the Linux 2.2.12 kernel sources. This page describes a single unified set of interdependent changes, but there are so many changes that I have broken up the log entry into paragraphs based on rough topical divisions of the work involved. Subset of verbatim Linux 2.2.12 sources imported on a vendor branch. * linux-src: New directory, see README for details. * README: New file, describes linux-src layout and procedures for tracking Linux source updates. Light modifications to linux-src files to avoid really bending over backwards with the glue macros. All modifications to files in linux-src are conditionalized by #ifdef _HURD_. * linux-src/include/linux/net.h [_HURD_] (struct socket): New members refcnt and identity; elide members fasync_list, file. * linux-src/include/linux/rtnetlink.h [! CONFIG_RTNETLINK] (rtnl_shlock, rtnl_shunlock) [! _HURD_]: Conditionalize contents on this, making these no-ops #ifdef _HURD_. * linux-src/net/core/dev.c [_HURD_] (dev_ioctl): Don't define the function, instead #define it to 0. * linux-src/net/ipv4/af_inet.c [_HURD_] (inet_ioctl): Likewise. * linux-src/net/ipv4/arp.c [_HURD_] (arp_ioctl): Likewise. * linux-src/net/ipv4/udp.c [_HURD_] (udp_ioctl): Likewise. * linux-src/net/ipv4/tcp.c [_HURD_] (tcp_ioctl): Likewise. [_HURD_] (tcp_tiocinq): New function, TIOCINQ code from tcp_ioctl. * linux-src/net/ipv4/devinet.c [_HURD_] (devinet_ioctl): Don't define the function, instead #define it to 0. [_HURD_] (configure_device): New function, cobbled from SIOCSIFADDR and SIOCSIFNETMASK code from devinet_ioctl. * glue-include/asm, glue-include/linux: New directories. These contain glue kludge headers that replace all of the Linux headers except checksum.h, and several of the Linux headers (the remainder come from linux-src/include/linux and are mostly unmodified). * glue-include/asm/atomic.h: New file, glue replacement header. * glue-include/asm/bitops.h: New file, glue replacement header. * glue-include/asm/byteorder.h: New file, glue replacement header. * glue-include/asm/checksum.h: New file, glue replacement header. * glue-include/asm/errno.h: New file, glue replacement header. * glue-include/asm/hardirq.h: New file, glue replacement header. * glue-include/asm/init.h: New file, glue replacement header. * glue-include/asm/segment.h: New file, glue replacement header. * glue-include/asm/spinlock.h: New file, glue replacement header. * glue-include/asm/system.h: New file, glue replacement header. * glue-include/asm/types.h: New file, glue replacement header. * glue-include/asm/uaccess.h: New file, glue replacement header. * glue-include/linux/autoconf.h: New file, glue replacement header. * glue-include/linux/binfmts.h: New file, glue replacement header. * glue-include/linux/config.h: New file, glue replacement header. * glue-include/linux/errno.h: New file, glue replacement header. * glue-include/linux/fcntl.h: New file, glue replacement header. * glue-include/linux/fs.h: New file, glue replacement header. * glue-include/linux/in.h: New file, glue replacement header. * glue-include/linux/in6.h: New file, glue replacement header. * glue-include/linux/interrupt.h: New file, glue replacement header. * glue-include/linux/ioctl.h: New file, glue replacement header. * glue-include/linux/ipv6.h: New file, glue replacement header. * glue-include/linux/kernel.h: New file, glue replacement header. * glue-include/linux/limits.h: New file, glue replacement header. * glue-include/linux/major.h: New file, glue replacement header. * glue-include/linux/malloc.h: New file, glue replacement header. * glue-include/linux/mm.h: New file, glue replacement header. * glue-include/linux/param.h: New file, glue replacement header. * glue-include/linux/personality.h: New file, glue replacement header. * glue-include/linux/poll.h: New file, glue replacement header. * glue-include/linux/proc_fs.h: New file, glue replacement header. * glue-include/linux/sched.h: New file, glue replacement header. * glue-include/linux/slab.h: New file, glue replacement header. * glue-include/linux/socket.h: New file, glue replacement header. * glue-include/linux/sockios.h: New file, glue replacement header. * glue-include/linux/stat.h: New file, glue replacement header. * glue-include/linux/string.h: New file, glue replacement header. * glue-include/linux/termios.h: New file, glue replacement header. * glue-include/linux/time.h: New file, glue replacement header. * glue-include/linux/timer.h: New file, glue replacement header. * glue-include/linux/timex.h: New file, glue replacement header. * glue-include/linux/types.h: New file, glue replacement header. * glue-include/linux/un.h: New file, glue replacement header. * glue-include/linux/version.h: New file, glue replacement header. * glue-include/linux/wait.h: New file, glue replacement header. * kmem_cache.c: New file. Glue code replaces Linux kmem_cache_t et al. * stubs.c: New file. No-op functions and stub variables for a few things the Linux networking code needs to link. * Makefile (core-srcs, arch-lib-srcs, ethernet-srcs, ipv4-srcs): New variables, listing sources used from linux-src subdirectories. (LINUXSRCS): Define using those. (SRCS): Remove devices.c; add kmem_cache.c, stubs.c. (UNUSEDSRC): Variable removed. (vpath %.c): Remove vpath for $(srcdir)/linux-inet directory. Add vpaths for $(srcdir)/linux-src subdirectories. (CPPFLAGS): Add -D_HURD_SYSTYPE defining it to $(asm_syntax) as a double-quoted string. Add -I's for glue-include and linux-src/include. * pfinet.h: Include , and not . (master_device): Remove decl. (global_lock, packet_queue_lock): Remove common defns. (global_lock, net_bh_lock): Declare them as externs. (struct sockaddr): Remove len member, make address member just a struct sockaddr rather than a 0-length array. (setup_loopback_device, become_task_protid, become_task): Remove decls. (ethernet_initialize): Declare it. (input_work_thread): Remove decl. (net_bh_thread): Declare it. (tcp_readable): Remove decl. (tcp_tiocinq): Declare it. * config.h: Rewritten based on Linux 2.2.12 set of CONFIG_* options. (CONFIG_NET, CONFIG_INET, CONFIG_SKB_LARGE): These are the only Linux config options we set. (CONFIG_IP_NOSIOCRT): New macro (not a proper config option, but used conveniently in the code). * ethernet.c (ethernet_set_multi): Take only one parameter. Remove assert, since we always get passed IGMP_ALL_HOSTS. (ethernet_thread): Make static. (ethernet_demuxer): Use __mutex_lock in place of mutex_lock, so as to get cthreads instead of linux/spinlock.h glue macros. Lock net_bh_lock instead of global_lock. Set SKB->protocol with eth_type_trans before calling netif_rx. (ethernet_initialize): New function, one-time initialization broken out of ethernet_open. (ethernet_open): Ports setup moved to ethernet_initialize. Don't use `errno' to avoid glue conflicts. Use get_privileged_ports here to get the master device port, and deallocate it after calling device_open. (ethernet_xmit): Use assert_perror. Only one arg to dev_kfree_skb now. (setup_ethernet_device): Change initializations for structure changes. Call dev_init_buffers and register_netdevice on the device. * timer-emul.c (all functions): Use __mutex_lock instead of mutex_lock. Adjust for renaming of `prevp' member to `prev' in struct timer_list. (mod_timer): New function. * socket.c (proto_ops): Variable removed. (net_families): New variable replaces it. (sock_register): Rewritten for new calling convention, set net_families rather than proto_ops. (make_sock_user, clean_socketport, sock_alloc, sock_release): Functions moved here from misc.c. * sched.c (packet_queue_lock): Variable removed. (net_bh_lock, net_bh_wakeup): New variables. (current): Variable removed (now a macro in the glue headers). (interruptible_sleep_on, wake_up_interruptible): Functions removed. They are replaced by inlines in the glue headers. (become_task, become_task_protid): Functions removed; they are replaced by macros in glue-include/linux/sched.h. (net_bh_worker): New function. * loopback.c: Completely rewritten, mostly copied from linux-2.2.12's drivers/net/loopback.c source file. * io-ops.c (all functions): Use __mutex_lock in place of mutex_lock. (S_io_write): Call ops->sendmsg instead of ops->write, which no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in msg_flags. (S_io_read): Call ops->recvmsg instead of ops->read, which no longer exists If O_NONBLOCK is set, pass MSG_DONTWAIT. (S_io_readable): Use USER->sock->data in place of USER->sock->sk. For SOCK_STREAM and SOCK_SEQPACKET types, call tcp_tiocinq. (S_io_set_all_openmodes, S_io_get_openmodes, S_io_set_some_openmodes, S_io_clear_some_openmodes): Member USER->sock->userflags is now renamed USER->sock->flags. (S_io_select): Completely rewritten using ops->poll. (select_wait): Function removed. (S_io_stat): Set st_mode to reflect S_IFSOCK. * socket-ops.c (all functions): Use __mutex_lock instead of mutex_lock. (S_socket_create): Don't set SOCK->ops or call SOCK->ops->create. Instead, call net_families[PF_INET]->create. (S_socket_listen): Remove extra checks; just call ops->listen. (S_socket_accept): Remove extra checks before ops->accept call. Avoid use of goto. (S_socket_connect): Remove extra checks; just call ops->connect. (S_socket_bind): Adjust for struct sock_addr changes. (S_socket_create_address): Likewise. (S_socket_whatis_address): Likewise. (S_socket_connect2): Don't diddle data structures after ops->socketpair call. (S_socket_getopt): Use sock_getsockopt if LEVEL is SOL_SOCKET. Accept any data size, not just sizeof (int). (S_socket_setopt): Use sock_setsockopt if LEVEL is SOL_SOCKET. (S_socket_send): Always use ops->sendmsg instead of ops->send or ops->sendto, which no longer exist. If O_NONBLOCK is set, set MSG_DONTWAIT in msg_flags. (S_socket_recv): Always use ops->recvmsg instead of ops->recv, which no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in flags. Check for error from S_socket_create_address. * main.c (find_device): Don't try to set ether_dev.pa_mask (it's gone). (main): Don't call init_devices. Call ethernet_initialize. Start net_bh_worker instead of input_work_thread. Don't call setup_loopback_device. Instead, take global_lock, do prepare_current, and then call sk_init, skb_init, inet_proto_init, and net_dev_init. Keep global_lock held while calling argp_parse. Call arrange_shutdown_notification only after all that. Fix error call for "contacting parent" to pass ERR instead of errno. * options.c (ADDR): #undef before defining macro. (parse_opt): #if 0 out EDESTADDRREQ check (I don't understand it). To apply settings, call configure_devices. (ADD_ADDR_OPT): #if 0 --address and --netmask options. Needs fixed. * misc.c (make_sock_user, clean_socketport, sock_alloc, sock_release): Functions moved to socket.c. (sock_release_peer): Function removed. (make_sockaddr_port): Use struct sockaddr_storage to size buffer. Fix size calculation for new struct sock_addr layout. Initialize sa_family and sa_len of new struct sock_addr. Remove the old Linux (2.0.??) network stack and the glue code for it. * linux-inet, asm, linux: Directories and all files removed. Some of the new files in glue-include came from the old glue headers in the asm and linux directories, but most were substantially modified. * devices.c: File removed. The equivalent glue is now elsewhere. --- pfinet/ChangeLog | 214 ++ pfinet/Makefile | 80 +- pfinet/README | 49 + pfinet/asm/bitops.h | 135 - pfinet/asm/segment.h | 21 - pfinet/asm/system.h | 10 - pfinet/config.h | 50 +- pfinet/devices.c | 60 - pfinet/ethernet.c | 96 +- pfinet/glue-include/asm/atomic.h | 27 + pfinet/glue-include/asm/bitops.h | 37 + pfinet/glue-include/asm/byteorder.h | 154 + pfinet/glue-include/asm/checksum.h | 5 + pfinet/glue-include/asm/errno.h | 3 + pfinet/glue-include/asm/hardirq.h | 1 + pfinet/glue-include/asm/init.h | 3 + pfinet/glue-include/asm/segment.h | 0 pfinet/glue-include/asm/spinlock.h | 75 + pfinet/glue-include/asm/system.h | 20 + pfinet/glue-include/asm/types.h | 1 + pfinet/glue-include/asm/uaccess.h | 47 + pfinet/glue-include/linux/autoconf.h | 0 pfinet/glue-include/linux/binfmts.h | 1 + pfinet/glue-include/linux/config.h | 1 + pfinet/glue-include/linux/errno.h | 13 + pfinet/glue-include/linux/fcntl.h | 1 + pfinet/glue-include/linux/fs.h | 21 + pfinet/glue-include/linux/in.h | 44 + pfinet/glue-include/linux/in6.h | 1 + pfinet/glue-include/linux/interrupt.h | 44 + pfinet/glue-include/linux/ioctl.h | 1 + pfinet/glue-include/linux/ipv6.h | 1 + pfinet/glue-include/linux/kernel.h | 78 + pfinet/glue-include/linux/limits.h | 8 + pfinet/glue-include/linux/major.h | 0 pfinet/glue-include/linux/malloc.h | 27 + pfinet/glue-include/linux/mm.h | 18 + pfinet/glue-include/linux/param.h | 1 + pfinet/glue-include/linux/personality.h | 1 + pfinet/glue-include/linux/poll.h | 24 + pfinet/glue-include/linux/proc_fs.h | 0 pfinet/glue-include/linux/sched.h | 176 + pfinet/glue-include/linux/slab.h | 0 pfinet/glue-include/linux/socket.h | 138 + pfinet/glue-include/linux/sockios.h | 0 pfinet/glue-include/linux/stat.h | 1 + pfinet/glue-include/linux/string.h | 1 + pfinet/glue-include/linux/termios.h | 1 + pfinet/glue-include/linux/time.h | 10 + pfinet/glue-include/linux/timer.h | 36 + pfinet/glue-include/linux/timex.h | 0 pfinet/glue-include/linux/types.h | 31 + pfinet/glue-include/linux/un.h | 0 pfinet/glue-include/linux/version.h | 3 + pfinet/glue-include/linux/wait.h | 32 + pfinet/io-ops.c | 208 +- pfinet/kmem_cache.c | 88 + pfinet/linux-inet/af_inet.c | 1578 --------- pfinet/linux-inet/arp.c | 1295 ------- pfinet/linux-inet/arp.h | 18 - pfinet/linux-inet/datagram.c | 210 -- pfinet/linux-inet/datalink.h | 17 - pfinet/linux-inet/dev.c | 1449 -------- pfinet/linux-inet/dev_mcast.c | 169 - pfinet/linux-inet/devinet.c | 213 -- pfinet/linux-inet/eth.c | 196 -- pfinet/linux-inet/eth.h | 35 - pfinet/linux-inet/icmp.c | 774 ----- pfinet/linux-inet/icmp.h | 38 - pfinet/linux-inet/igmp.c | 390 --- pfinet/linux-inet/ip.c | 2427 ------------- pfinet/linux-inet/ip.h | 130 - pfinet/linux-inet/ip_fw.c | 1016 ------ pfinet/linux-inet/ipx.c | 1947 ----------- pfinet/linux-inet/ipx.h | 84 - pfinet/linux-inet/ipxcall.h | 2 - pfinet/linux-inet/p8022.c | 98 - pfinet/linux-inet/p8022.h | 2 - pfinet/linux-inet/p8022call.h | 2 - pfinet/linux-inet/p8023.c | 35 - pfinet/linux-inet/packet.c | 410 --- pfinet/linux-inet/pe2.c | 35 - pfinet/linux-inet/proc.c | 257 -- pfinet/linux-inet/protocol.c | 177 - pfinet/linux-inet/protocol.h | 59 - pfinet/linux-inet/psnap.c | 123 - pfinet/linux-inet/psnap.h | 2 - pfinet/linux-inet/psnapcall.h | 2 - pfinet/linux-inet/rarp.c | 491 --- pfinet/linux-inet/rarp.h | 14 - pfinet/linux-inet/raw.c | 319 -- pfinet/linux-inet/raw.h | 34 - pfinet/linux-inet/route.c | 684 ---- pfinet/linux-inet/route.h | 54 - pfinet/linux-inet/skbuff.c | 573 ---- pfinet/linux-inet/snmp.h | 107 - pfinet/linux-inet/sock.c | 574 ---- pfinet/linux-inet/sock.h | 316 -- pfinet/linux-inet/tcp.c | 5121 ---------------------------- pfinet/linux-inet/tcp.h | 142 - pfinet/linux-inet/timer.c | 264 -- pfinet/linux-inet/udp.c | 740 ---- pfinet/linux-inet/udp.h | 50 - pfinet/linux-inet/utils.c | 91 - pfinet/linux-src/include/linux/net.h | 12 +- pfinet/linux-src/include/linux/rtnetlink.h | 8 +- pfinet/linux-src/net/core/dev.c | 200 +- pfinet/linux-src/net/ipv4/af_inet.c | 116 +- pfinet/linux-src/net/ipv4/arp.c | 64 +- pfinet/linux-src/net/ipv4/devinet.c | 70 +- pfinet/linux-src/net/ipv4/tcp.c | 159 +- pfinet/linux-src/net/ipv4/udp.c | 104 +- pfinet/linux/autoconf.h | 0 pfinet/linux/config.h | 0 pfinet/linux/errno.h | 8 - pfinet/linux/etherdevice.h | 41 - pfinet/linux/fcntl.h | 1 - pfinet/linux/icmp.h | 81 - pfinet/linux/if.h | 156 - pfinet/linux/if_arp.h | 91 - pfinet/linux/if_ether.h | 80 - pfinet/linux/igmp.h | 67 - pfinet/linux/in.h | 1 - pfinet/linux/inet.h | 6 - pfinet/linux/interrupt.h | 11 - pfinet/linux/ip.h | 121 - pfinet/linux/ip_fw.h | 147 - pfinet/linux/ipx.h | 78 - pfinet/linux/kernel.h | 44 - pfinet/linux/major.h | 0 pfinet/linux/malloc.h | 10 - pfinet/linux/mm.h | 16 - pfinet/linux/net.h | 146 - pfinet/linux/netdevice.h | 235 -- pfinet/linux/notifier.h | 96 - pfinet/linux/param.h | 1 - pfinet/linux/route.h | 69 - pfinet/linux/sched.h | 81 - pfinet/linux/skbuff.h | 286 -- pfinet/linux/socket.h | 27 - pfinet/linux/sockios.h | 0 pfinet/linux/stat.h | 1 - pfinet/linux/string.h | 1 - pfinet/linux/tcp.h | 112 - pfinet/linux/termios.h | 1 - pfinet/linux/time.h | 13 - pfinet/linux/timer.h | 27 - pfinet/linux/types.h | 16 - pfinet/linux/udp.h | 29 - pfinet/linux/un.h | 0 pfinet/linux/wait.h | 23 - pfinet/loopback.c | 166 +- pfinet/main.c | 48 +- pfinet/misc.c | 144 +- pfinet/mutations.h | 2 +- pfinet/options.c | 67 +- pfinet/pfinet.h | 26 +- pfinet/sched.c | 82 +- pfinet/socket-ops.c | 309 +- pfinet/socket.c | 100 +- pfinet/stubs.c | 70 + pfinet/timer-emul.c | 34 +- 162 files changed, 2639 insertions(+), 26127 deletions(-) create mode 100644 pfinet/README delete mode 100644 pfinet/asm/bitops.h delete mode 100644 pfinet/asm/segment.h delete mode 100644 pfinet/asm/system.h delete mode 100644 pfinet/devices.c create mode 100644 pfinet/glue-include/asm/atomic.h create mode 100644 pfinet/glue-include/asm/bitops.h create mode 100644 pfinet/glue-include/asm/byteorder.h create mode 100644 pfinet/glue-include/asm/checksum.h create mode 100644 pfinet/glue-include/asm/errno.h create mode 100644 pfinet/glue-include/asm/hardirq.h create mode 100644 pfinet/glue-include/asm/init.h create mode 100644 pfinet/glue-include/asm/segment.h create mode 100644 pfinet/glue-include/asm/spinlock.h create mode 100644 pfinet/glue-include/asm/system.h create mode 100644 pfinet/glue-include/asm/types.h create mode 100644 pfinet/glue-include/asm/uaccess.h create mode 100644 pfinet/glue-include/linux/autoconf.h create mode 100644 pfinet/glue-include/linux/binfmts.h create mode 100644 pfinet/glue-include/linux/config.h create mode 100644 pfinet/glue-include/linux/errno.h create mode 100644 pfinet/glue-include/linux/fcntl.h create mode 100644 pfinet/glue-include/linux/fs.h create mode 100644 pfinet/glue-include/linux/in.h create mode 100644 pfinet/glue-include/linux/in6.h create mode 100644 pfinet/glue-include/linux/interrupt.h create mode 100644 pfinet/glue-include/linux/ioctl.h create mode 100644 pfinet/glue-include/linux/ipv6.h create mode 100644 pfinet/glue-include/linux/kernel.h create mode 100644 pfinet/glue-include/linux/limits.h create mode 100644 pfinet/glue-include/linux/major.h create mode 100644 pfinet/glue-include/linux/malloc.h create mode 100644 pfinet/glue-include/linux/mm.h create mode 100644 pfinet/glue-include/linux/param.h create mode 100644 pfinet/glue-include/linux/personality.h create mode 100644 pfinet/glue-include/linux/poll.h create mode 100644 pfinet/glue-include/linux/proc_fs.h create mode 100644 pfinet/glue-include/linux/sched.h create mode 100644 pfinet/glue-include/linux/slab.h create mode 100644 pfinet/glue-include/linux/socket.h create mode 100644 pfinet/glue-include/linux/sockios.h create mode 100644 pfinet/glue-include/linux/stat.h create mode 100644 pfinet/glue-include/linux/string.h create mode 100644 pfinet/glue-include/linux/termios.h create mode 100644 pfinet/glue-include/linux/time.h create mode 100644 pfinet/glue-include/linux/timer.h create mode 100644 pfinet/glue-include/linux/timex.h create mode 100644 pfinet/glue-include/linux/types.h create mode 100644 pfinet/glue-include/linux/un.h create mode 100644 pfinet/glue-include/linux/version.h create mode 100644 pfinet/glue-include/linux/wait.h create mode 100644 pfinet/kmem_cache.c delete mode 100644 pfinet/linux-inet/af_inet.c delete mode 100644 pfinet/linux-inet/arp.c delete mode 100644 pfinet/linux-inet/arp.h delete mode 100644 pfinet/linux-inet/datagram.c delete mode 100644 pfinet/linux-inet/datalink.h delete mode 100644 pfinet/linux-inet/dev.c delete mode 100644 pfinet/linux-inet/dev_mcast.c delete mode 100644 pfinet/linux-inet/devinet.c delete mode 100644 pfinet/linux-inet/eth.c delete mode 100644 pfinet/linux-inet/eth.h delete mode 100644 pfinet/linux-inet/icmp.c delete mode 100644 pfinet/linux-inet/icmp.h delete mode 100644 pfinet/linux-inet/igmp.c delete mode 100644 pfinet/linux-inet/ip.c delete mode 100644 pfinet/linux-inet/ip.h delete mode 100644 pfinet/linux-inet/ip_fw.c delete mode 100644 pfinet/linux-inet/ipx.c delete mode 100644 pfinet/linux-inet/ipx.h delete mode 100644 pfinet/linux-inet/ipxcall.h delete mode 100644 pfinet/linux-inet/p8022.c delete mode 100644 pfinet/linux-inet/p8022.h delete mode 100644 pfinet/linux-inet/p8022call.h delete mode 100644 pfinet/linux-inet/p8023.c delete mode 100644 pfinet/linux-inet/packet.c delete mode 100644 pfinet/linux-inet/pe2.c delete mode 100644 pfinet/linux-inet/proc.c delete mode 100644 pfinet/linux-inet/protocol.c delete mode 100644 pfinet/linux-inet/protocol.h delete mode 100644 pfinet/linux-inet/psnap.c delete mode 100644 pfinet/linux-inet/psnap.h delete mode 100644 pfinet/linux-inet/psnapcall.h delete mode 100644 pfinet/linux-inet/rarp.c delete mode 100644 pfinet/linux-inet/rarp.h delete mode 100644 pfinet/linux-inet/raw.c delete mode 100644 pfinet/linux-inet/raw.h delete mode 100644 pfinet/linux-inet/route.c delete mode 100644 pfinet/linux-inet/route.h delete mode 100644 pfinet/linux-inet/skbuff.c delete mode 100644 pfinet/linux-inet/snmp.h delete mode 100644 pfinet/linux-inet/sock.c delete mode 100644 pfinet/linux-inet/sock.h delete mode 100644 pfinet/linux-inet/tcp.c delete mode 100644 pfinet/linux-inet/tcp.h delete mode 100644 pfinet/linux-inet/timer.c delete mode 100644 pfinet/linux-inet/udp.c delete mode 100644 pfinet/linux-inet/udp.h delete mode 100644 pfinet/linux-inet/utils.c delete mode 100644 pfinet/linux/autoconf.h delete mode 100644 pfinet/linux/config.h delete mode 100644 pfinet/linux/errno.h delete mode 100644 pfinet/linux/etherdevice.h delete mode 100644 pfinet/linux/fcntl.h delete mode 100644 pfinet/linux/icmp.h delete mode 100644 pfinet/linux/if.h delete mode 100644 pfinet/linux/if_arp.h delete mode 100644 pfinet/linux/if_ether.h delete mode 100644 pfinet/linux/igmp.h delete mode 100644 pfinet/linux/in.h delete mode 100644 pfinet/linux/inet.h delete mode 100644 pfinet/linux/interrupt.h delete mode 100644 pfinet/linux/ip.h delete mode 100644 pfinet/linux/ip_fw.h delete mode 100644 pfinet/linux/ipx.h delete mode 100644 pfinet/linux/kernel.h delete mode 100644 pfinet/linux/major.h delete mode 100644 pfinet/linux/malloc.h delete mode 100644 pfinet/linux/mm.h delete mode 100644 pfinet/linux/net.h delete mode 100644 pfinet/linux/netdevice.h delete mode 100644 pfinet/linux/notifier.h delete mode 100644 pfinet/linux/param.h delete mode 100644 pfinet/linux/route.h delete mode 100644 pfinet/linux/sched.h delete mode 100644 pfinet/linux/skbuff.h delete mode 100644 pfinet/linux/socket.h delete mode 100644 pfinet/linux/sockios.h delete mode 100644 pfinet/linux/stat.h delete mode 100644 pfinet/linux/string.h delete mode 100644 pfinet/linux/tcp.h delete mode 100644 pfinet/linux/termios.h delete mode 100644 pfinet/linux/time.h delete mode 100644 pfinet/linux/timer.h delete mode 100644 pfinet/linux/types.h delete mode 100644 pfinet/linux/udp.h delete mode 100644 pfinet/linux/un.h delete mode 100644 pfinet/linux/wait.h create mode 100644 pfinet/stubs.c diff --git a/pfinet/ChangeLog b/pfinet/ChangeLog index 255dd7b4..cd0acf7f 100644 --- a/pfinet/ChangeLog +++ b/pfinet/ChangeLog @@ -1,3 +1,217 @@ +2000-02-03 Roland McGrath + + Complete overhaul of pfinet based on the IPv4 networking code from the + Linux 2.2.12 kernel sources. This page describes a single unified set + of interdependent changes, but there are so many changes that I have + broken up the log entry into paragraphs based on rough topical + divisions of the work involved. + + Subset of verbatim Linux 2.2.12 sources imported on a vendor branch. + * linux-src: New directory, see README for details. + * README: New file, describes linux-src layout and procedures for + tracking Linux source updates. + + Light modifications to linux-src files to avoid really bending over + backwards with the glue macros. All modifications to files in + linux-src are conditionalized by #ifdef _HURD_. + * linux-src/include/linux/net.h [_HURD_] (struct socket): New members + refcnt and identity; elide members fasync_list, file. + * linux-src/include/linux/rtnetlink.h [! CONFIG_RTNETLINK] + (rtnl_shlock, rtnl_shunlock) [! _HURD_]: Conditionalize contents on + this, making these no-ops #ifdef _HURD_. + * linux-src/net/core/dev.c [_HURD_] (dev_ioctl): Don't define the + function, instead #define it to 0. + * linux-src/net/ipv4/af_inet.c [_HURD_] (inet_ioctl): Likewise. + * linux-src/net/ipv4/arp.c [_HURD_] (arp_ioctl): Likewise. + * linux-src/net/ipv4/udp.c [_HURD_] (udp_ioctl): Likewise. + * linux-src/net/ipv4/tcp.c [_HURD_] (tcp_ioctl): Likewise. + [_HURD_] (tcp_tiocinq): New function, TIOCINQ code from tcp_ioctl. + * linux-src/net/ipv4/devinet.c [_HURD_] (devinet_ioctl): Don't define + the function, instead #define it to 0. + [_HURD_] (configure_device): New function, cobbled from SIOCSIFADDR + and SIOCSIFNETMASK code from devinet_ioctl. + + * glue-include/asm, glue-include/linux: New directories. + These contain glue kludge headers that replace all of the + Linux headers except checksum.h, and several of + the Linux headers (the remainder come from + linux-src/include/linux and are mostly unmodified). + * glue-include/asm/atomic.h: New file, glue replacement header. + * glue-include/asm/bitops.h: New file, glue replacement header. + * glue-include/asm/byteorder.h: New file, glue replacement header. + * glue-include/asm/checksum.h: New file, glue replacement header. + * glue-include/asm/errno.h: New file, glue replacement header. + * glue-include/asm/hardirq.h: New file, glue replacement header. + * glue-include/asm/init.h: New file, glue replacement header. + * glue-include/asm/segment.h: New file, glue replacement header. + * glue-include/asm/spinlock.h: New file, glue replacement header. + * glue-include/asm/system.h: New file, glue replacement header. + * glue-include/asm/types.h: New file, glue replacement header. + * glue-include/asm/uaccess.h: New file, glue replacement header. + * glue-include/linux/autoconf.h: New file, glue replacement header. + * glue-include/linux/binfmts.h: New file, glue replacement header. + * glue-include/linux/config.h: New file, glue replacement header. + * glue-include/linux/errno.h: New file, glue replacement header. + * glue-include/linux/fcntl.h: New file, glue replacement header. + * glue-include/linux/fs.h: New file, glue replacement header. + * glue-include/linux/in.h: New file, glue replacement header. + * glue-include/linux/in6.h: New file, glue replacement header. + * glue-include/linux/interrupt.h: New file, glue replacement header. + * glue-include/linux/ioctl.h: New file, glue replacement header. + * glue-include/linux/ipv6.h: New file, glue replacement header. + * glue-include/linux/kernel.h: New file, glue replacement header. + * glue-include/linux/limits.h: New file, glue replacement header. + * glue-include/linux/major.h: New file, glue replacement header. + * glue-include/linux/malloc.h: New file, glue replacement header. + * glue-include/linux/mm.h: New file, glue replacement header. + * glue-include/linux/param.h: New file, glue replacement header. + * glue-include/linux/personality.h: New file, glue replacement header. + * glue-include/linux/poll.h: New file, glue replacement header. + * glue-include/linux/proc_fs.h: New file, glue replacement header. + * glue-include/linux/sched.h: New file, glue replacement header. + * glue-include/linux/slab.h: New file, glue replacement header. + * glue-include/linux/socket.h: New file, glue replacement header. + * glue-include/linux/sockios.h: New file, glue replacement header. + * glue-include/linux/stat.h: New file, glue replacement header. + * glue-include/linux/string.h: New file, glue replacement header. + * glue-include/linux/termios.h: New file, glue replacement header. + * glue-include/linux/time.h: New file, glue replacement header. + * glue-include/linux/timer.h: New file, glue replacement header. + * glue-include/linux/timex.h: New file, glue replacement header. + * glue-include/linux/types.h: New file, glue replacement header. + * glue-include/linux/un.h: New file, glue replacement header. + * glue-include/linux/version.h: New file, glue replacement header. + * glue-include/linux/wait.h: New file, glue replacement header. + + * kmem_cache.c: New file. Glue code replaces Linux kmem_cache_t et al. + * stubs.c: New file. No-op functions and stub variables for a few + things the Linux networking code needs to link. + + * Makefile (core-srcs, arch-lib-srcs, ethernet-srcs, ipv4-srcs): New + variables, listing sources used from linux-src subdirectories. + (LINUXSRCS): Define using those. + (SRCS): Remove devices.c; add kmem_cache.c, stubs.c. + (UNUSEDSRC): Variable removed. + (vpath %.c): Remove vpath for $(srcdir)/linux-inet directory. + Add vpaths for $(srcdir)/linux-src subdirectories. + (CPPFLAGS): Add -D_HURD_SYSTYPE defining it to $(asm_syntax) as a + double-quoted string. Add -I's for glue-include and linux-src/include. + + * pfinet.h: Include , and not . + (master_device): Remove decl. + (global_lock, packet_queue_lock): Remove common defns. + (global_lock, net_bh_lock): Declare them as externs. + (struct sockaddr): Remove len member, make address member just a + struct sockaddr rather than a 0-length array. + (setup_loopback_device, become_task_protid, become_task): Remove decls. + (ethernet_initialize): Declare it. + (input_work_thread): Remove decl. + (net_bh_thread): Declare it. + (tcp_readable): Remove decl. + (tcp_tiocinq): Declare it. + + * config.h: Rewritten based on Linux 2.2.12 set of CONFIG_* options. + (CONFIG_NET, CONFIG_INET, CONFIG_SKB_LARGE): These are the only + Linux config options we set. + (CONFIG_IP_NOSIOCRT): New macro (not a proper config option, but + used conveniently in the code). + * ethernet.c (ethernet_set_multi): Take only one parameter. + Remove assert, since we always get passed IGMP_ALL_HOSTS. + (ethernet_thread): Make static. + (ethernet_demuxer): Use __mutex_lock in place of mutex_lock, so as to + get cthreads instead of linux/spinlock.h glue macros. Lock + net_bh_lock instead of global_lock. Set SKB->protocol with + eth_type_trans before calling netif_rx. + (ethernet_initialize): New function, one-time initialization broken + out of ethernet_open. + (ethernet_open): Ports setup moved to ethernet_initialize. + Don't use `errno' to avoid glue conflicts. + Use get_privileged_ports here to get the master device port, and + deallocate it after calling device_open. + (ethernet_xmit): Use assert_perror. Only one arg to dev_kfree_skb now. + (setup_ethernet_device): Change initializations for structure changes. + Call dev_init_buffers and register_netdevice on the device. + * timer-emul.c (all functions): Use __mutex_lock instead of mutex_lock. + Adjust for renaming of `prevp' member to `prev' in struct timer_list. + (mod_timer): New function. + * socket.c (proto_ops): Variable removed. + (net_families): New variable replaces it. + (sock_register): Rewritten for new calling convention, set + net_families rather than proto_ops. + (make_sock_user, clean_socketport, sock_alloc, sock_release): + Functions moved here from misc.c. + * sched.c (packet_queue_lock): Variable removed. + (net_bh_lock, net_bh_wakeup): New variables. + (current): Variable removed (now a macro in the glue headers). + (interruptible_sleep_on, wake_up_interruptible): Functions removed. + They are replaced by inlines in the glue headers. + (become_task, become_task_protid): Functions removed; they are + replaced by macros in glue-include/linux/sched.h. + (net_bh_worker): New function. + * loopback.c: Completely rewritten, mostly copied from linux-2.2.12's + drivers/net/loopback.c source file. + + * io-ops.c (all functions): Use __mutex_lock in place of mutex_lock. + (S_io_write): Call ops->sendmsg instead of ops->write, + which no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in + msg_flags. + (S_io_read): Call ops->recvmsg instead of ops->read, + which no longer exists If O_NONBLOCK is set, pass MSG_DONTWAIT. + (S_io_readable): Use USER->sock->data in place of USER->sock->sk. + For SOCK_STREAM and SOCK_SEQPACKET types, call tcp_tiocinq. + (S_io_set_all_openmodes, S_io_get_openmodes, S_io_set_some_openmodes, + S_io_clear_some_openmodes): Member USER->sock->userflags is now + renamed USER->sock->flags. + (S_io_select): Completely rewritten using ops->poll. + (select_wait): Function removed. + (S_io_stat): Set st_mode to reflect S_IFSOCK. + * socket-ops.c (all functions): Use __mutex_lock instead of mutex_lock. + (S_socket_create): Don't set SOCK->ops or call SOCK->ops->create. + Instead, call net_families[PF_INET]->create. + (S_socket_listen): Remove extra checks; just call ops->listen. + (S_socket_accept): Remove extra checks before ops->accept call. + Avoid use of goto. + (S_socket_connect): Remove extra checks; just call ops->connect. + (S_socket_bind): Adjust for struct sock_addr changes. + (S_socket_create_address): Likewise. + (S_socket_whatis_address): Likewise. + (S_socket_connect2): Don't diddle data structures after + ops->socketpair call. + (S_socket_getopt): Use sock_getsockopt if LEVEL is SOL_SOCKET. + Accept any data size, not just sizeof (int). + (S_socket_setopt): Use sock_setsockopt if LEVEL is SOL_SOCKET. + (S_socket_send): Always use ops->sendmsg instead of ops->send or + ops->sendto, which no longer exist. If O_NONBLOCK is set, set + MSG_DONTWAIT in msg_flags. + (S_socket_recv): Always use ops->recvmsg instead of ops->recv, which + no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in flags. + Check for error from S_socket_create_address. + + * main.c (find_device): Don't try to set ether_dev.pa_mask (it's gone). + (main): Don't call init_devices. Call ethernet_initialize. + Start net_bh_worker instead of input_work_thread. Don't call + setup_loopback_device. Instead, take global_lock, do prepare_current, + and then call sk_init, skb_init, inet_proto_init, and net_dev_init. + Keep global_lock held while calling argp_parse. + Call arrange_shutdown_notification only after all that. + Fix error call for "contacting parent" to pass ERR instead of errno. + * options.c (ADDR): #undef before defining macro. + (parse_opt): #if 0 out EDESTADDRREQ check (I don't understand it). + To apply settings, call configure_devices. + (ADD_ADDR_OPT): #if 0 --address and --netmask options. Needs fixed. + * misc.c (make_sock_user, clean_socketport, sock_alloc, sock_release): + Functions moved to socket.c. + (sock_release_peer): Function removed. + (make_sockaddr_port): Use struct sockaddr_storage to size buffer. + Fix size calculation for new struct sock_addr layout. + Initialize sa_family and sa_len of new struct sock_addr. + + Remove the old Linux (2.0.??) network stack and the glue code for it. + * linux-inet, asm, linux: Directories and all files removed. + Some of the new files in glue-include came from the old glue headers + in the asm and linux directories, but most were substantially modified. + * devices.c: File removed. The equivalent glue is now elsewhere. + 2000-01-27 Roland McGrath * mapped-time.h: Include . diff --git a/pfinet/Makefile b/pfinet/Makefile index e86512a9..81e76480 100644 --- a/pfinet/Makefile +++ b/pfinet/Makefile @@ -1,6 +1,5 @@ -# -# Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. -# Written by Michael I. Bushnell. +# +# Copyright (C) 1995,96,97,2000 Free Software Foundation, Inc. # # This file is part of the GNU Hurd. # @@ -18,21 +17,57 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. -dir := pfinet -makemode := server -LINUXSRCS= af_inet.c arp.c datagram.c dev.c dev_mcast.c devinet.c eth.c \ - icmp.c igmp.c ip.c \ - proc.c protocol.c raw.c route.c skbuff.c sock.c \ - tcp.c timer.c udp.c utils.c -UNUSEDSRC = packet.c ipx.c ip_fw.c p8022.c p8023.c pe2.c psnap.c rarp.c -SRCS = sched.c timer-emul.c devices.c socket.c main.c ethernet.c \ - io-ops.c socket-ops.c misc.c time.c options.c loopback.c -MIGSRCS = ioServer.c socketServer.c startup_notifyServer.c -OBJS= $(subst .c,.o,$(LINUXSRCS) $(SRCS) $(MIGSRCS)) -LCLHDRS= config.h mapped-time.h mutations.h pfinet.h -LINUXHDRS = arp.h datalink.h eth.h icmp.h ip.h ipx.h ipxcall.h p8022.h \ - p8022call.h protocol.h psnap.h psnapcall.h rarp.h raw.h route.h \ - snmp.h sock.h tcp.h udp.h +dir := pfinet +makemode := server + +core-srcs := datagram.c \ + dev.c \ + dev_mcast.c \ + dst.c \ + iovec.c \ + neighbour.c \ + skbuff.c \ + sock.c \ + utils.c +arch-lib-srcs := checksum.c old-checksum.c +ethernet-srcs := eth.c +ipv4-srcs := af_inet.c \ + arp.c \ + devinet.c \ + fib_frontend.c \ + fib_hash.c \ + fib_semantics.c \ + icmp.c \ + igmp.c \ + ip_forward.c \ + ip_fragment.c \ + ip_input.c \ + ip_options.c \ + ip_output.c \ + ip_sockglue.c \ + protocol.c \ + raw.c \ + route.c \ + syncookies.c \ + sysctl_net_ipv4.c \ + tcp.c \ + tcp_input.c \ + tcp_ipv4.c \ + tcp_output.c \ + tcp_timer.c \ + timer.c \ + udp.c \ + utils.c +LINUXSRCS = $(core-srcs) $(ethernet-srcs) $(ipv4-srcs) $(arch-lib-srcs) +SRCS = sched.c timer-emul.c socket.c main.c ethernet.c \ + io-ops.c socket-ops.c misc.c time.c options.c loopback.c \ + kmem_cache.c stubs.c +MIGSRCS = ioServer.c socketServer.c startup_notifyServer.c +OBJS := $(patsubst %.c,%.o,$(LINUXSRCS) $(SRCS) $(MIGSRCS)) +LCLHDRS = config.h mapped-time.h mutations.h pfinet.h +LINUXHDRS = arp.h datalink.h eth.h icmp.h ip.h ipx.h ipxcall.h p8022.h \ + p8022call.h protocol.h psnap.h psnapcall.h \ + rarp.h raw.h route.h snmp.h sock.h tcp.h udp.h FROBBEDLINUXHEADERS = autoconf.h config.h errno.h etherdevice.h fcntl.h \ icmp.h if.h if_arp.h if_ether.h igmp.h in.h inet.h interrupt.h \ ip.h ip_fw.h ipx.h kernel.h major.h malloc.h mm.h net.h netdevice.h \ @@ -46,9 +81,14 @@ target = pfinet include ../Makeconf -vpath %.c $(srcdir)/linux-inet +vpath %.c $(addprefix $(srcdir)/linux-src/net/,core ethernet ipv4) +vpath %.c $(srcdir)/linux-src/arch/$(asm_syntax)/lib +vpath %.S $(srcdir)/linux-src/arch/$(asm_syntax)/lib -CPPFLAGS += -imacros $(srcdir)/config.h +CPPFLAGS += '-D_HURD_SYSTYPE="$(asm_syntax)"' \ + -imacros $(srcdir)/config.h \ + -I$(srcdir)/glue-include \ + -I$(srcdir)/linux-src/include io-MIGSFLAGS = -imacros $(srcdir)/mutations.h socket-MIGSFLAGS = -imacros $(srcdir)/mutations.h diff --git a/pfinet/README b/pfinet/README new file mode 100644 index 00000000..decbb307 --- /dev/null +++ b/pfinet/README @@ -0,0 +1,49 @@ +The Hurd's pfinet server is based on networking code taken from +the Linux kernel sources, initially version 2.2.12 of Linux. +The subset of the Linux kernel sources used for pfinet is kept +in the linux-src subdirectory. + +This file describes the procedures for tracking new Linux kernel versions +and updating the Linux networking code in the Hurd CVS repository. + +The verbatim Linux kernel sources are kept on a vendor branch in CVS. To +simplify the process of importing and merging new versions, I have mostly +imported whole subdirectories of the linux source tree rather than just the +precise subset of files we are actually using. However, for the arch/*/lib +and include/asm-* subdirectories I have taken just the checksum files (the +only thing we use from the machine-dependent Linux code); and I have +removed the extraneous whole subdirectories within the include/linux and +include/net directories. It is my intention to leave the remaining +extraneous files in the CVS repository, but to include in the distributions +only the files we are actually using (they will be listed in the Makefile). +They could also be left on the vendor branch and removed from the trunk, but +I think that would have more disadvantages than advantages. + +The initial import was done with the following commands. It is crucial to +use `-I !' in the `cvs import' command because of the directory +linux-src/net/core/ ("core" is in CVS's default list of names to ignore). + +mkdir import-tmp +cd import-tmp +bunzip2 < linux-2.2.12.tar.bz2 | tar xf - linux/{'arch/*/lib/*checksum*','include/asm-*/checksum.h',include/{linux,net},net/{core,ipv4,ethernet}} +cd linux +rm -rf include/{net,linux}/*/ +cvs -d `cat ../../CVS/Root` import -I ! -ko -m "Import of Linux 2.2.12 subset (ipv4 stack and related)" hurd/pfinet/linux-src Linux Linux_2_2_12 + +It should work to repeat the same procedure with later versions to upgrade +the `Linux' vendor branch. Please import only verbatim official Linux +kernel sources, and stick to the tag name schema. If you don't already +know how to merge the new vendor release into the trunk and finish the +upgrade, then you probably should not be doing this anyway. + +On the main branch, only a few files within the linux-src tree are +modified, and those only lightly (the changes are described in ChangeLog). +Linux header files that are heavily modified or wholly replaced for use in +pfinet go into the glue-include/ subdirectory instead of modifying +linux-src files in place. Whole C source files can just be replaced with +new files in the top-level pfinet source directory. When modifications to +a file in linux-src are justified, the modifications should always be +conditionalized by #ifdef _HURD_. + + + -- Roland McGrath 2000-02-03 diff --git a/pfinet/asm/bitops.h b/pfinet/asm/bitops.h deleted file mode 100644 index ee339bd6..00000000 --- a/pfinet/asm/bitops.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef _I386_BITOPS_H -#define _I386_BITOPS_H - -/* - * Copyright 1992, Linus Torvalds. - */ - -/* - * These have to be done with inline assembly: that way the bit-setting - * is guaranteed to be atomic. All bit operations return 0 if the bit - * was cleared before the operation and != 0 if it was not. - * - * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). - */ - -/* - * Some hacks to defeat gcc over-optimizations.. - */ -struct __dummy { unsigned long a[100]; }; -#define ADDR (*(struct __dummy *) addr) - -extern __inline__ int set_bit(int nr, void * addr) -{ - int oldbit; - - __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"r" (nr)); - return oldbit; -} - -extern __inline__ int clear_bit(int nr, void * addr) -{ - int oldbit; - - __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"r" (nr)); - return oldbit; -} - -extern __inline__ int change_bit(int nr, void * addr) -{ - int oldbit; - - __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"r" (nr)); - return oldbit; -} - -/* - * This routine doesn't need to be atomic, but it's faster to code it - * this way. - */ -extern __inline__ int test_bit(int nr, void * addr) -{ - int oldbit; - - __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit) - :"m" (ADDR),"r" (nr)); - return oldbit; -} - -/* - * Find-bit routines.. - */ -extern inline int find_first_zero_bit(void * addr, unsigned size) -{ - int res; - - if (!size) - return 0; - __asm__(" - cld - movl $-1,%%eax - repe; scasl - je 1f - subl $4,%%edi - movl (%%edi),%%eax - notl %%eax - bsfl %%eax,%%edx - jmp 2f -1: xorl %%edx,%%edx -2: subl %%ebx,%%edi - shll $3,%%edi - addl %%edi,%%edx" - :"=d" (res) - :"c" ((size + 31) >> 5), "D" (addr), "b" (addr) - :"ax", "bx", "cx", "di"); - return res; -} - -extern inline int find_next_zero_bit (void * addr, int size, int offset) -{ - unsigned long * p = ((unsigned long *) addr) + (offset >> 5); - int set = 0, bit = offset & 31, res; - - if (bit) { - /* - * Look for zero in first byte - */ - __asm__(" - bsfl %1,%0 - jne 1f - movl $32, %0 -1: " - : "=r" (set) - : "r" (~(*p >> bit))); - if (set < (32 - bit)) - return set + offset; - set = 32 - bit; - p++; - } - /* - * No zero yet, search remaining full bytes for a zero - */ - res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr)); - return (offset + set + res); -} - -/* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. - */ -extern inline unsigned long ffz(unsigned long word) -{ - __asm__("bsfl %1,%0" - :"=r" (word) - :"r" (~word)); - return word; -} - -#endif /* _I386_BITOPS_H */ diff --git a/pfinet/asm/segment.h b/pfinet/asm/segment.h deleted file mode 100644 index 34c35b96..00000000 --- a/pfinet/asm/segment.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _HACK_ASM_SEGMENT_H_ -#define _HACK_ASM_SEGMENT_H_ - -#include - -#define get_fs_long(addr) (*(long *)(addr)) -#define get_user_long(addr) (*(long *)(addr)) - -#define get_fs_byte(addr) (*(char *)(addr)) -#define get_user_byte(addr) (*(char *)(addr)) - -#define put_fs_long(x,addr) (*(long *)(addr) = (x)) -#define put_user_long(x,addr) (*(long *)(addr) = (x) - -#define put_fs_byte(x,addr) (*(char *)(addr) = (x)) -#define put_user_byte(x,addr) (*(char *)(addr) = (x)) - -#define memcpy_fromfs(a,b,s) (memcpy (a, b, s)) -#define memcpy_tofs(a,b,s) (memcpy (a, b, s)) - -#endif diff --git a/pfinet/asm/system.h b/pfinet/asm/system.h deleted file mode 100644 index f828c3bb..00000000 --- a/pfinet/asm/system.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _HACK_ASM_SYSTEM_H_ -#define _HACK_ASM_SYSTEM_H_ - -#define intr_count 0 -#define save_flags(x) ((x) = 0) -#define restore_flags(x) -#define cli() -#define sti() - -#endif diff --git a/pfinet/config.h b/pfinet/config.h index eb8314ef..ce079620 100644 --- a/pfinet/config.h +++ b/pfinet/config.h @@ -1,28 +1,36 @@ -#define __KERNEL__ -#define _HURD_ +#define __KERNEL__ 1 +#undef __SMP__ + +#define _HURD_ 1 #define ENONET ENETUNREACH -#define CONFIG_INET -#define CONFIG_NET -/* #undef CONFIG_INET_RARP */ -/* #undef CONFIG_IP_MULTICAST */ -/* #undef CONFIG_IP_FORWARD */ -/* #undef CONFIG_IP_FIREWALL */ -/* #undef CONFIG_IP_FIREWALL_DEBUG */ -/* #undef CONFIG_IP_FIREWALL_VERBOSE */ -/* #undef DEBUG_CONFIG_IP_FIREWALL */ -/* #undef CONFIG_IP_ACCT */ +#define CONFIG_NET 1 +#define CONFIG_INET 1 + +#undef CONFIG_IPX +#undef CONFIG_ATALK +#undef CONFIG_PACKET +#undef CONFIG_UNIX +#undef CONFIG_NETLINK +#undef CONFIG_RTNETLINK + +#undef CONFIG_FIREWALL +#undef CONFIG_FILTER + +#undef CONFIG_IP_MULTICAST +#undef CONFIG_IP_ROUTER +#undef CONFIG_IP_ADVANCED_ROUTER +#undef CONFIG_IP_PNP +#undef CONFIG_IP_ALIAS + +#undef CONFIG_NET_IPIP +#undef CONFIG_NET_IPGRE -/* #undef CONFIG_SKB_CHECK */ +#undef CONFIG_SYN_COOKIES -/* #undef CONFIG_TCP_NAGLE_OFF */ -/* #undef CONFIG_AX25 */ -/* #undef CONFIG_IPX */ -/* #undef CONFIG_ATALK */ -/* #undef CONFIG_SLAVE_BALANCING */ +#undef CONFIG_INET_RARP -/* #undef CONFIG_INET_PCTCP */ -/* #undef CONFIG_INET_SNARL */ +#define CONFIG_SKB_LARGE 1 -/* #undef CONFIG_I_AM_A_BROKEN_BSD_WEENIE */ +#define CONFIG_IP_NOSIOCRT 1 /* How convenient. */ diff --git a/pfinet/devices.c b/pfinet/devices.c deleted file mode 100644 index 34d865a6..00000000 --- a/pfinet/devices.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc. - Written by Michael I. Bushnell, p/BSG. - - This file is part of the GNU Hurd. - - The GNU Hurd is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. - - The GNU Hurd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ - -#include "pfinet.h" - -struct device *dev_base; -struct device loopback_dev; - -device_t master_device; - -static struct condition more_packets = CONDITION_INITIALIZER; - -void -init_devices (void) -{ - error_t err; - - err = get_privileged_ports (0, &master_device); - if (err) - { - perror ("Cannot fetch master device port"); - exit (1); - } - - dev_base = 0; -} - -void -mark_bh (int arg) -{ - condition_broadcast (&more_packets); -} - -any_t -input_work_thread (any_t arg) -{ - mutex_lock (&global_lock); - for (;;) - { - condition_wait (&more_packets, &global_lock); - net_bh (0); - } -} diff --git a/pfinet/ethernet.c b/pfinet/ethernet.c index 85162fd8..1b81e1aa 100644 --- a/pfinet/ethernet.c +++ b/pfinet/ethernet.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1995,96,98,99,2000 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -18,15 +18,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ +#include "pfinet.h" + #include #include -#include -#include #include #include #include -#include "pfinet.h" +#include +#include +#include + device_t ether_port; @@ -53,9 +56,8 @@ ethernet_stop (struct device *dev) } void -ethernet_set_multi (struct device *dev, int numaddrs, void *addrs) +ethernet_set_multi (struct device *dev) { - assert (numaddrs == 0); } static short ether_filter[] = @@ -68,7 +70,7 @@ static int ether_filter_len = sizeof (ether_filter) / sizeof (short); static struct port_bucket *etherport_bucket; -any_t +static any_t ethernet_thread (any_t arg) { ports_manage_port_operations_one_thread (etherport_bucket, @@ -98,7 +100,7 @@ ethernet_demuxer (mach_msg_header_t *inp, datalen = ETH_HLEN + msg->packet_type.msgt_number - sizeof (struct packet_header); - mutex_lock (&global_lock); + __mutex_lock (&net_bh_lock); skb = alloc_skb (datalen, GFP_ATOMIC); skb->len = datalen; skb->dev = ðer_dev; @@ -110,32 +112,46 @@ ethernet_demuxer (mach_msg_header_t *inp, datalen - ETH_HLEN); /* Drop it on the queue. */ + skb->protocol = eth_type_trans (skb, ðer_dev); netif_rx (skb); - mutex_unlock (&global_lock); + __mutex_unlock (&net_bh_lock); return 1; } +void +ethernet_initialize (void) +{ + etherport_bucket = ports_create_bucket (); + etherreadclass = ports_create_class (0, 0); + + cthread_detach (cthread_fork (ethernet_thread, 0)); +} + int ethernet_open (struct device *dev) { error_t err; + device_t master_device; - if (ether_port != MACH_PORT_NULL) - return 0; + assert (ether_port == MACH_PORT_NULL); - etherreadclass = ports_create_class (0, 0); - errno = ports_create_port (etherreadclass, etherport_bucket, - sizeof (struct port_info), &readpt); - assert_perror (errno); + err = ports_create_port (etherreadclass, etherport_bucket, + sizeof (struct port_info), &readpt); + assert_perror (err); readptname = ports_get_right (readpt); mach_port_insert_right (mach_task_self (), readptname, readptname, MACH_MSG_TYPE_MAKE_SEND); mach_port_set_qlimit (mach_task_self (), readptname, MACH_PORT_QLIMIT_MAX); + err = get_privileged_ports (0, &master_device); + if (err) + error (2, err, "cannot get device master port"); + err = device_open (master_device, D_WRITE | D_READ, dev->name, ðer_port); + mach_port_deallocate (mach_task_self (), master_device); if (err) error (2, err, "%s", dev->name); @@ -144,7 +160,6 @@ ethernet_open (struct device *dev) ether_filter, ether_filter_len); if (err) error (2, err, "%s", dev->name); - cthread_detach (cthread_fork (ethernet_thread, 0)); return 0; } @@ -154,12 +169,12 @@ int ethernet_xmit (struct sk_buff *skb, struct device *dev) { u_int count; - int err; + error_t err; err = device_write (ether_port, D_NOWAIT, 0, skb->data, skb->len, &count); - assert (err == 0); + assert_perror (err); assert (count == skb->len); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } @@ -169,36 +184,36 @@ setup_ethernet_device (char *name) struct net_status netstat; u_int count; int net_address[2]; - int i; error_t err; - etherport_bucket = ports_create_bucket (); + bzero (ðer_dev, sizeof ether_dev); - /* Interface buffers. */ - ether_dev.name = name; - for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init (ðer_dev.buffs[i]); + ether_dev.name = strdup (name); - /* Functions */ - ether_dev.open = ethernet_open; + /* Functions. These ones are the true "hardware layer" in Linux. */ + ether_dev.open = 0; /* We set up before calling dev_open. */ ether_dev.stop = ethernet_stop; ether_dev.hard_start_xmit = ethernet_xmit; - ether_dev.hard_header = eth_header; - ether_dev.rebuild_header = eth_rebuild_header; - ether_dev.type_trans = eth_type_trans; ether_dev.get_stats = ethernet_get_stats; ether_dev.set_multicast_list = ethernet_set_multi; + /* These are the ones set by drivers/net/net_init.c::ether_setup. */ + ether_dev.hard_header = eth_header; + ether_dev.rebuild_header = eth_rebuild_header; + ether_dev.hard_header_cache = eth_header_cache; + ether_dev.header_cache_update = eth_header_cache_update; + ether_dev.hard_header_parse = eth_header_parse; + /* We can't do these two (and we never try anyway). */ + /* ether_dev.change_mtu = eth_change_mtu; */ + /* ether_dev.set_mac_address = eth_mac_addr; */ + /* Some more fields */ ether_dev.type = ARPHRD_ETHER; - ether_dev.hard_header_len = sizeof (struct ethhdr); + ether_dev.hard_header_len = ETH_HLEN; ether_dev.addr_len = ETH_ALEN; - for (i = 0; i < 6; i++) - ether_dev.broadcast[i] = 0xff; + memset (ether_dev.broadcast, 0xff, ETH_ALEN); ether_dev.flags = IFF_BROADCAST | IFF_MULTICAST; - ether_dev.family = AF_INET; /* hmm. */ - ether_dev.pa_addr = ether_dev.pa_brdaddr = ether_dev.pa_mask = 0; - ether_dev.pa_alen = sizeof (unsigned long); + dev_init_buffers (ðer_dev); ethernet_open (ðer_dev); @@ -222,8 +237,11 @@ setup_ethernet_device (char *name) net_address[1] = ntohl (net_address[1]); bcopy (net_address, ether_dev.dev_addr, ETH_ALEN); - /* That should be enough. */ + /* That should be enough. */ - ether_dev.next = dev_base; - dev_base = ðer_dev; + /* This call adds the device to the `dev_base' chain, + initializes its `ifindex' member (which matters!), + and tells the protocol stacks about the device. */ + err = - register_netdevice (ðer_dev); + assert_perror (err); } diff --git a/pfinet/glue-include/asm/atomic.h b/pfinet/glue-include/asm/atomic.h new file mode 100644 index 00000000..d053854e --- /dev/null +++ b/pfinet/glue-include/asm/atomic.h @@ -0,0 +1,27 @@ +#ifndef _HACK_ASM_ATOMIC_H +#define _HACK_ASM_ATOMIC_H + +/* We don't need atomicity in the Linux code because we serialize all + entries to it. */ + +typedef struct { int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +static __inline__ void atomic_add(int i, atomic_t *v) { v->counter += i; } +static __inline__ void atomic_sub(int i, atomic_t *v) { v->counter -= i; } +static __inline__ void atomic_inc(atomic_t *v) { ++v->counter; } +static __inline__ void atomic_dec(atomic_t *v) { --v->counter; } +static __inline__ int atomic_dec_and_test(atomic_t *v) +{ return --v->counter == 0; } +static __inline__ int atomic_inc_and_test_greater_zero(atomic_t *v) +{ return ++v->counter > 0; } + +#define atomic_clear_mask(mask, addr) (*(addr) &= ~(mask)) +#define atomic_set_mask(mask, addr) (*(addr) |= (mask)) + + +#endif diff --git a/pfinet/glue-include/asm/bitops.h b/pfinet/glue-include/asm/bitops.h new file mode 100644 index 00000000..8c5a835d --- /dev/null +++ b/pfinet/glue-include/asm/bitops.h @@ -0,0 +1,37 @@ +#ifndef _HACK_ASM_BITOPS_H +#define _HACK_ASM_BITOPS_H + +/* We don't need atomicity in the Linux code because we serialize all + entries to it. */ + +#include + +#define BITOPS_WORD(nr, addr) (((uint32_t *) (addr))[(nr) / 32]) +#define BITOPS_MASK(nr) (1 << ((nr) & 31)) + +static __inline__ void set_bit (int nr, void *addr) +{ BITOPS_WORD (nr, addr) |= BITOPS_MASK (nr); } + +static __inline__ void clear_bit (int nr, void *addr) +{ BITOPS_WORD (nr, addr) &= ~BITOPS_MASK (nr); } + +static __inline__ void change_bit (int nr, void *addr) +{ BITOPS_WORD (nr, addr) ^= BITOPS_MASK (nr); } + +static __inline__ int test_bit (int nr, void *addr) +{ return BITOPS_WORD (nr, addr) & BITOPS_MASK (nr); } + +static __inline__ int test_and_set_bit (int nr, void *addr) +{ + int res = BITOPS_WORD (nr, addr) & BITOPS_MASK (nr); + BITOPS_WORD (nr, addr) |= BITOPS_MASK (nr); + return res; +} + +#define find_first_zero_bit #error loser +#define find_next_zero_bit #error loser + +#define ffz(word) (ffs (~(unsigned int) (word)) - 1) + + +#endif diff --git a/pfinet/glue-include/asm/byteorder.h b/pfinet/glue-include/asm/byteorder.h new file mode 100644 index 00000000..ee1da1f4 --- /dev/null +++ b/pfinet/glue-include/asm/byteorder.h @@ -0,0 +1,154 @@ +/* Provide the specified-byte-order access functions used in the Linux + kernel, implemented as macros in terms of the GNU libc facilities. */ + +#ifndef _HACK_ASM_BYTEORDER_H +#define _HACK_ASM_BYTEORDER_H 1 + +#include +#include + +#define BO_cvt(bits, from, to, x) \ + ((from) == (to) ? (u_int##bits##_t) (x) : bswap_##bits (x)) +#define BO_cvtp(bits, from, to, p) \ + BO_cvt (bits, from, to, *(const u_int##bits##_t *) (p)) +#define BO_cvts(bits, from, to, p) \ + ({ const u_int##bits##_t *_p = (p); *_p = BO_cvt (bits, from, to, *_p); }) + +#define __cpu_to_le64(x) BO_cvt (64, BYTE_ORDER, LITTLE_ENDIAN, (x)) +#define __le64_to_cpu(x) BO_cvt (64, LITTLE_ENDIAN, BYTE_ORDER, (x)) +#define __cpu_to_le32(x) BO_cvt (32, BYTE_ORDER, LITTLE_ENDIAN, (x)) +#define __le32_to_cpu(x) BO_cvt (32, LITTLE_ENDIAN, BYTE_ORDER, (x)) +#define __cpu_to_le16(x) BO_cvt (16, BYTE_ORDER, LITTLE_ENDIAN, (x)) +#define __le16_to_cpu(x) BO_cvt (16, LITTLE_ENDIAN, BYTE_ORDER, (x)) +#define __cpu_to_be64(x) BO_cvt (64, BYTE_ORDER, BIG_ENDIAN, (x)) +#define __be64_to_cpu(x) BO_cvt (64, BIG_ENDIAN, BYTE_ORDER, (x)) +#define __cpu_to_be32(x) BO_cvt (32, BYTE_ORDER, BIG_ENDIAN, (x)) +#define __be32_to_cpu(x) BO_cvt (32, BIG_ENDIAN, BYTE_ORDER, (x)) +#define __cpu_to_be16(x) BO_cvt (16, BYTE_ORDER, BIG_ENDIAN, (x)) +#define __be16_to_cpu(x) BO_cvt (16, BIG_ENDIAN, BYTE_ORDER, (x)) +#define __cpu_to_le64p(p) BO_cvtp (64, BYTE_ORDER, LITTLE_ENDIAN, (p)) +#define __le64_to_cpup(p) BO_cvtp (64, LITTLE_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_le32p(p) BO_cvtp (32, BYTE_ORDER, LITTLE_ENDIAN, (p)) +#define __le32_to_cpup(p) BO_cvtp (32, LITTLE_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_le16p(p) BO_cvtp (16, BYTE_ORDER, LITTLE_ENDIAN, (p)) +#define __le16_to_cpup(p) BO_cvtp (16, LITTLE_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_be64p(p) BO_cvtp (64, BYTE_ORDER, BIG_ENDIAN, (p)) +#define __be64_to_cpup(p) BO_cvtp (64, BIG_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_be32p(p) BO_cvtp (32, BYTE_ORDER, BIG_ENDIAN, (p)) +#define __be32_to_cpup(p) BO_cvtp (32, BIG_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_be16p(p) BO_cvtp (16, BYTE_ORDER, BIG_ENDIAN, (p)) +#define __be16_to_cpup(p) BO_cvtp (16, BIG_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_le64s(p) BO_cvts (64, BYTE_ORDER, LITTLE_ENDIAN, (p)) +#define __le64_to_cpus(p) BO_cvts (64, LITTLE_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_le32s(p) BO_cvts (32, BYTE_ORDER, LITTLE_ENDIAN, (p)) +#define __le32_to_cpus(p) BO_cvts (32, LITTLE_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_le16s(p) BO_cvts (16, BYTE_ORDER, LITTLE_ENDIAN, (p)) +#define __le16_to_cpus(p) BO_cvts (16, LITTLE_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_be64s(p) BO_cvts (64, BYTE_ORDER, BIG_ENDIAN, (p)) +#define __be64_to_cpus(p) BO_cvts (64, BIG_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_be32s(p) BO_cvts (32, BYTE_ORDER, BIG_ENDIAN, (p)) +#define __be32_to_cpus(p) BO_cvts (32, BIG_ENDIAN, BYTE_ORDER, (p)) +#define __cpu_to_be16s(p) BO_cvts (16, BYTE_ORDER, BIG_ENDIAN, (p)) +#define __be16_to_cpus(p) BO_cvts (16, BIG_ENDIAN, BYTE_ORDER, (p)) + +#define cpu_to_le64 __cpu_to_le64 +#define le64_to_cpu __le64_to_cpu +#define cpu_to_le32 __cpu_to_le32 +#define le32_to_cpu __le32_to_cpu +#define cpu_to_le16 __cpu_to_le16 +#define le16_to_cpu __le16_to_cpu +#define cpu_to_be64 __cpu_to_be64 +#define be64_to_cpu __be64_to_cpu +#define cpu_to_be32 __cpu_to_be32 +#define be32_to_cpu __be32_to_cpu +#define cpu_to_be16 __cpu_to_be16 +#define be16_to_cpu __be16_to_cpu +#define cpu_to_le64p __cpu_to_le64p +#define le64_to_cpup __le64_to_cpup +#define cpu_to_le32p __cpu_to_le32p +#define le32_to_cpup __le32_to_cpup +#define cpu_to_le16p __cpu_to_le16p +#define le16_to_cpup __le16_to_cpup +#define cpu_to_be64p __cpu_to_be64p +#define be64_to_cpup __be64_to_cpup +#define cpu_to_be32p __cpu_to_be32p +#define be32_to_cpup __be32_to_cpup +#define cpu_to_be16p __cpu_to_be16p +#define be16_to_cpup __be16_to_cpup +#define cpu_to_le64s __cpu_to_le64s +#define le64_to_cpus __le64_to_cpus +#define cpu_to_le32s __cpu_to_le32s +#define le32_to_cpus __le32_to_cpus +#define cpu_to_le16s __cpu_to_le16s +#define le16_to_cpus __le16_to_cpus +#define cpu_to_be64s __cpu_to_be64s +#define be64_to_cpus __be64_to_cpus +#define cpu_to_be32s __cpu_to_be32s +#define be32_to_cpus __be32_to_cpus +#define cpu_to_be16s __cpu_to_be16s +#define be16_to_cpus __be16_to_cpus + + +#if BYTE_ORDER == BIG_ENDIAN +# define __BIG_ENDIAN_BITFIELD +#elif BYTE_ORDER == LITTLE_ENDIAN +# define __LITTLE_ENDIAN_BITFIELD +#else +# error __FOO_ENDIAN_BITFIELD +#endif + + +#include /* for htonl et al */ + +/* Though the optimized macros defined by glibc do the constant magic, + there are places in the Linux code that use these in constant-only + places like initializers, and the ({...}) expressions the macros use are + not valid in those contexts. */ +#if BYTE_ORDER == BIG_ENDIAN +# if !defined(__constant_htonl) +# define __constant_htonl(x) (x) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) (x) +# endif +#elif BYTE_ORDER == LITTLE_ENDIAN +# if !defined(__constant_htonl) +# define __constant_htonl(x) \ + ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +# endif +#else +# error "Don't know if bytes are big- or little-endian!" +#endif + +/* The transformation is the same in both directions. */ +#define __constant_ntohl __constant_htonl +#define __constant_ntohs __constant_htons + + +/* Some Linux code (e.g. ) uses #ifdef __BIG_ENDIAN et al. + This is not real wonderful with the glibc definitions, where + __BIG_ENDIAN et al are always defined (as values for __BYTE_ORDER). */ +#if BYTE_ORDER == BIG_ENDIAN +#undef __LITTLE_ENDIAN +#elif BYTE_ORDER == LITTLE_ENDIAN +#undef __BIG_ENDIAN +#endif +#undef __PDP_ENDIAN + +/* Since we've now broken anything that does glibc-style tests, + make sure they break loudly rather than silently. Any headers + that need __BYTE_ORDER will just have to be included before + we diddle with __BIG_ENDIAN or __LITTLE_ENDIAN above. */ +#undef __BYTE_ORDER +#define __BYTE_ORDER ?????crash????? + + +#endif /* asm/byteorder.h */ diff --git a/pfinet/glue-include/asm/checksum.h b/pfinet/glue-include/asm/checksum.h new file mode 100644 index 00000000..5bcf7551 --- /dev/null +++ b/pfinet/glue-include/asm/checksum.h @@ -0,0 +1,5 @@ +/* This is the only file from the Linux include/asm-* directory + that we use, so we use this magic file here rather than making a + symlink asm -> .../linux-src/include/asm-SYSTYPE somewhere. */ + +#include "../../linux-src/include/asm-" _HURD_SYSTYPE "/checksum.h" diff --git a/pfinet/glue-include/asm/errno.h b/pfinet/glue-include/asm/errno.h new file mode 100644 index 00000000..7afb6fdc --- /dev/null +++ b/pfinet/glue-include/asm/errno.h @@ -0,0 +1,3 @@ +/* This is used only by checksum.S; the C code uses . */ + +#define EFAULT 42 /* only used in unreached code */ diff --git a/pfinet/glue-include/asm/hardirq.h b/pfinet/glue-include/asm/hardirq.h new file mode 100644 index 00000000..c73d7dcb --- /dev/null +++ b/pfinet/glue-include/asm/hardirq.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/asm/init.h b/pfinet/glue-include/asm/init.h new file mode 100644 index 00000000..2331be7c --- /dev/null +++ b/pfinet/glue-include/asm/init.h @@ -0,0 +1,3 @@ +#define __init +#define __initdata +#define __initfunc(x) x diff --git a/pfinet/glue-include/asm/segment.h b/pfinet/glue-include/asm/segment.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/asm/spinlock.h b/pfinet/glue-include/asm/spinlock.h new file mode 100644 index 00000000..937c5d05 --- /dev/null +++ b/pfinet/glue-include/asm/spinlock.h @@ -0,0 +1,75 @@ +#ifndef _HACK_ASM_SPINLOCK_H_ +#define _HACK_ASM_SPINLOCK_H_ + +#include + +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED (spinlock_t) { } + +#undef spin_lock_init +#undef spin_lock +#undef spin_unlock + +#define spin_lock_init(lock) ((void) (lock)) +#define spin_lock(lock) ((void) (lock)) +#define spin_trylock(lock) ((void) (lock), 1) +#define spin_unlock_wait(lock) ((void) (lock)) +#define spin_unlock(lock) ((void) (lock)) +#define spin_lock_irq(lock) ((void) (lock)) +#define spin_unlock_irq(lock) ((void) (lock)) +#define spin_lock_irqsave(lock, flags) ((void) (lock), (void) (flags)) +#define spin_unlock_irqrestore(lock, flags) ((void) (lock), (void) (flags)) + +typedef struct { } rwlock_t; +#define read_lock(rw) do { } while(0) +#define write_lock(rw) do { } while(0) +#define write_unlock(rw) do { } while(0) +#define read_unlock(rw) do { } while(0) + +#if 0 +#include + +typedef struct mutex spinlock_t; + +#undef spin_lock_init +#undef spin_lock +#undef spin_unlock + +#define SPIN_LOCK_UNLOCKED MUTEX_INITIALIZER +#define spin_lock_init(lock) ({ __mutex_init (lock); }) +#define spin_lock(lock) ({ __mutex_lock (lock); }) +#define spin_trylock(lock) ({ __mutex_trylock (lock); }) +#define spin_unlock_wait(lock) ({ __mutex_unlock (lock); }) +#define spin_unlock(lock) ({ __mutex_unlock (lock); }) +#define spin_lock_irq(lock) ({ __mutex_lock (lock); }) +#define spin_unlock_irq(lock) ({ __mutex_unlock (lock); }) + +#define spin_lock_irqsave(lock, flags) \ + do { flags = 0; __mutex_lock (lock); } while (0) +#define spin_unlock_irqrestore(lock, flags) ({ __mutex_unlock (lock); }) + + +typedef struct rwlock rwlock_t; + +#define read_lock(rw) rwlock_reader_lock(rw) +#define write_lock(rw) rwlock_writer_lock(rw) +#define write_unlock(rw) rwlock_writer_unlock(rw) +#define read_unlock(rw) rwlock_reader_unlock(rw) + +#endif + + +#define read_lock_irq(lock) read_lock(lock) +#define read_unlock_irq(lock) read_unlock(lock) +#define write_lock_irq(lock) write_lock(lock) +#define write_unlock_irq(lock) write_unlock(lock) + +#define read_lock_irqsave(lock, flags) \ + do { (flags) = 0; read_lock(lock); } while (0) +#define read_unlock_irqrestore(lock, flags) read_unlock(lock) +#define write_lock_irqsave(lock, flags) \ + do { (flags) = 0; write_lock(lock); } while (0) +#define write_unlock_irqrestore(lock, flags) write_unlock(lock) + + +#endif diff --git a/pfinet/glue-include/asm/system.h b/pfinet/glue-include/asm/system.h new file mode 100644 index 00000000..1a5d61cd --- /dev/null +++ b/pfinet/glue-include/asm/system.h @@ -0,0 +1,20 @@ +#ifndef _HACK_ASM_SYSTEM_H +#define _HACK_ASM_SYSTEM_H + +/* We don't need atomicity in the Linux code because we serialize all + entries to it. */ + +#include + +#define xchg(ptr, x) \ + ({ \ + __typeof__ (*(ptr)) *_ptr = (ptr), _x = *_ptr; \ + (uintptr_t) *_ptr = (x); _x; \ + }) + +#define mb() ((void) 0) /* memory barrier */ +#define rmb() mb() +#define wmb() mb() + + +#endif diff --git a/pfinet/glue-include/asm/types.h b/pfinet/glue-include/asm/types.h new file mode 100644 index 00000000..ee9b980a --- /dev/null +++ b/pfinet/glue-include/asm/types.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/asm/uaccess.h b/pfinet/glue-include/asm/uaccess.h new file mode 100644 index 00000000..d8373797 --- /dev/null +++ b/pfinet/glue-include/asm/uaccess.h @@ -0,0 +1,47 @@ +#ifndef _HACK_ASM_UACCESS_H_ +#define _HACK_ASM_UACCESS_H_ + +#include + + +#define MAKE_MM_SEG(s) XXX +#define KERNEL_DS XXX +#define USER_DS XXX + +#define get_ds() XXX +#define get_fs() XXX +#define set_fs(x) XXX + +#define segment_eq(a,b) XXX + +extern int __verify_write(const void *, unsigned long); +#define __verify_write XXX + +#define __addr_ok(addr) (1) +#define __range_ok(addr,size) (1) +#define access_ok(type,addr,size) (1) + +#define put_user(x,ptr) (*(ptr) = (x), 0) +#define get_user(x,ptr) ((x) = *(ptr), 0) + +/* + * The "xxx_ret" versions return constant specified in third argument, if + * something bad happens. These macros can be optimized for the + * case of just returning from the function xxx_ret is used. + */ + +#define put_user_ret(x,ptr,ret) ({ if (put_user(x,ptr)) return ret; }) + +#define get_user_ret(x,ptr,ret) ({ if (get_user(x,ptr)) return ret; }) + + +#define copy_to_user(to,from,n) (memcpy ((to), (from), (n)), 0) +#define copy_from_user(to,from,n) (memcpy ((to), (from), (n)), 0) +#define clear_user(mem, len) (bzero ((mem), (len)), 0) + +#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) + +#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) + + +#endif diff --git a/pfinet/glue-include/linux/autoconf.h b/pfinet/glue-include/linux/autoconf.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/linux/binfmts.h b/pfinet/glue-include/linux/binfmts.h new file mode 100644 index 00000000..c8229dad --- /dev/null +++ b/pfinet/glue-include/linux/binfmts.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/config.h b/pfinet/glue-include/linux/config.h new file mode 100644 index 00000000..be1e4d3f --- /dev/null +++ b/pfinet/glue-include/linux/config.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/errno.h b/pfinet/glue-include/linux/errno.h new file mode 100644 index 00000000..7afcd9fd --- /dev/null +++ b/pfinet/glue-include/linux/errno.h @@ -0,0 +1,13 @@ +#ifndef _HACK_ERRNO_H +#define _HACK_ERRNO_H + +#include +#include + +#define ERESTARTSYS EINTR +#define ENOPKG ENOSYS +#define ENOIOCTLCMD ENOTTY + +#undef errno + +#endif diff --git a/pfinet/glue-include/linux/fcntl.h b/pfinet/glue-include/linux/fcntl.h new file mode 100644 index 00000000..cd304557 --- /dev/null +++ b/pfinet/glue-include/linux/fcntl.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/fs.h b/pfinet/glue-include/linux/fs.h new file mode 100644 index 00000000..45dbb19f --- /dev/null +++ b/pfinet/glue-include/linux/fs.h @@ -0,0 +1,21 @@ +#ifndef _HACK_FS_H +#define _HACK_FS_H + +#include + +/* Hackery */ +struct inode +{ + union + { + int i_garbage; + struct socket socket_i; /* icmp.c actually needs this!! */ + } u; +}; +#define i_uid u.i_garbage +#define i_gid u.i_garbage +#define i_sock u.i_garbage +#define i_ino u.i_garbage +#define i_mode u.i_garbage + +#endif diff --git a/pfinet/glue-include/linux/in.h b/pfinet/glue-include/linux/in.h new file mode 100644 index 00000000..074c70e3 --- /dev/null +++ b/pfinet/glue-include/linux/in.h @@ -0,0 +1,44 @@ +#ifndef _HACK_IN_H_ +#define _HACK_IN_H_ + +#include + +/* IP_MTU_DISCOVER values */ +#define IP_PMTUDISC_DONT 0 /* Never send DF frames */ +#define IP_PMTUDISC_WANT 1 /* Use per route hints */ +#define IP_PMTUDISC_DO 2 /* Always DF */ + +/* These need to appear somewhere around here */ +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_DEFAULT_MULTICAST_LOOP 1 + +struct ip_mreqn +{ + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_address; /* local IP address of interface */ + int imr_ifindex; /* Interface index */ +}; + +struct in_pktinfo +{ + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + + +/* contains the htonl type stuff.. */ +#include + +#ifdef __KERNEL__ +/* Some random defines to make it easier in the kernel.. */ +#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000)) +#define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000)) +#define BADCLASS(x) (((x) & htonl(0xf0000000)) == htonl(0xf0000000)) +#define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000)) +#define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000)) + +#endif + + +#endif diff --git a/pfinet/glue-include/linux/in6.h b/pfinet/glue-include/linux/in6.h new file mode 100644 index 00000000..260020a6 --- /dev/null +++ b/pfinet/glue-include/linux/in6.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/interrupt.h b/pfinet/glue-include/linux/interrupt.h new file mode 100644 index 00000000..5f485e32 --- /dev/null +++ b/pfinet/glue-include/linux/interrupt.h @@ -0,0 +1,44 @@ +#ifndef _HACK_INTERRUPT_H_ +#define _HACK_INTERRUPT_H_ + +#include +#include "pfinet.h" + +#define in_interrupt() (0) +#define synchronize_irq() ((void) 0) + +#define synchronize_bh() ((void) 0) /* XXX ? */ + +/* The code that can call these are already entered holding + global_lock, which locks out the net_bh worker thread. */ +#define start_bh_atomic() ((void) 0) +#define end_bh_atomic() ((void) 0) +/* +extern struct mutex net_bh_lock; +#define start_bh_atomic() __mutex_lock (&net_bh_lock) +#define end_bh_atomic() __mutex_unlock (&net_bh_lock) +*/ + +/* See sched.c::net_bh_worker comments. */ +extern struct condition net_bh_wakeup; + +#define NET_BH 0xb00bee51 + +/* The only call to this ever reached is in net/core/dev.c::netif_rx, + to announce having enqueued a packet on `backlog'. */ +static inline void +mark_bh (int bh) +{ + assert (bh == NET_BH); + condition_broadcast (&net_bh_wakeup); +} + +void net_bh (void); +static inline void +init_bh (int bh, void (*fn) (void)) +{ + assert (bh == NET_BH); + assert (fn == &net_bh); +} + +#endif diff --git a/pfinet/glue-include/linux/ioctl.h b/pfinet/glue-include/linux/ioctl.h new file mode 100644 index 00000000..6ec92cf7 --- /dev/null +++ b/pfinet/glue-include/linux/ioctl.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/ipv6.h b/pfinet/glue-include/linux/ipv6.h new file mode 100644 index 00000000..374f9b1e --- /dev/null +++ b/pfinet/glue-include/linux/ipv6.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/kernel.h b/pfinet/glue-include/linux/kernel.h new file mode 100644 index 00000000..a0e101b9 --- /dev/null +++ b/pfinet/glue-include/linux/kernel.h @@ -0,0 +1,78 @@ +#ifndef _HACK_KERNEL_H +#define _HACK_KERNEL_H + +#include +#include +#include + + +/* These don't actually matter since our locking protocols are different. */ +#define barrier() ((void)0) /*__asm__ __volatile__("": : :"memory") */ + +#define NORET_TYPE /**/ +#define ATTRIB_NORET __attribute__((noreturn)) +#define NORET_AND noreturn, +#define FASTCALL(x) x + +/* XXX do something syslogy */ +#define KERN_EMERG +#define KERN_ALERT +#define KERN_CRIT +#define KERN_ERR +#define KERN_WARNING +#define KERN_NOTICE +#define KERN_INFO +#define KERN_DEBUG + +#define panic(str...) (printk (str), assert (!"panic")) + +/* + * Display an IP address in readable format. + */ + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + + +#include +#include + +#define printk printf + +extern inline int +getname (const char *name, char **newp) +{ + *newp = malloc (strlen (name) + 1); + strcpy (*newp, name); + return 0; +} + +extern inline void +putname (char *p) +{ + free (p); +} + +/* These two functions are used only to send SIGURG. But I can't + find any SIGIO code at all. So we'll just punt on that; clearly + Linux is missing the point. SIGURG should only be sent for + sockets that have explicitly requested it. */ +extern inline int +kill_proc (int pid, int signo, int priv) +{ + assert (signo == SIGURG); + return 0; +} + +extern inline int +kill_pg (int pgrp, int signo, int priv) +{ + assert (signo == SIGURG); + return 0; +} + + +#endif diff --git a/pfinet/glue-include/linux/limits.h b/pfinet/glue-include/linux/limits.h new file mode 100644 index 00000000..856c3bde --- /dev/null +++ b/pfinet/glue-include/linux/limits.h @@ -0,0 +1,8 @@ +#ifndef _HACK_LIMITS_H +#define _HACK_LIMITS_H + +#include + +#define UIO_MAXIOV 1024 /* probably 1 would do */ + +#endif diff --git a/pfinet/glue-include/linux/major.h b/pfinet/glue-include/linux/major.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/linux/malloc.h b/pfinet/glue-include/linux/malloc.h new file mode 100644 index 00000000..46ae1051 --- /dev/null +++ b/pfinet/glue-include/linux/malloc.h @@ -0,0 +1,27 @@ +#ifndef _HACK_MALLOC_H_ +#define _HACK_MALLOC_H_ + +#include + +#include + +static inline void *kmalloc (size_t sz, int ignored) { return malloc (sz); } +static inline void kfree (void *ptr) { free (ptr); } +static inline void kfree_s (void *ptr, size_t sz) { free (ptr); } +#define free(x) kfree(x) /* just don't ask */ + + +typedef struct kmem_cache_s kmem_cache_t; + +#define SLAB_HWCACHE_ALIGN 0 /* flag everybody uses */ +#define SLAB_ATOMIC 0 + + +extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, + void (*)(void *, kmem_cache_t *, unsigned long), + void (*)(void *, kmem_cache_t *, unsigned long)); +extern void *kmem_cache_alloc(kmem_cache_t *, int); +extern void kmem_cache_free(kmem_cache_t *, void *); + + +#endif diff --git a/pfinet/glue-include/linux/mm.h b/pfinet/glue-include/linux/mm.h new file mode 100644 index 00000000..a6f28e00 --- /dev/null +++ b/pfinet/glue-include/linux/mm.h @@ -0,0 +1,18 @@ +#ifndef _HACK_MM_H_ +#define _HACK_MM_H_ + +#include +#include + +/* All memory addresses are presumptively valid, because they are + all internal. */ +#define verify_area(a,b,c) 0 + +#define VERIFY_READ 0 +#define VERIFY_WRITE 0 +#define GFP_ATOMIC 0 +#define GFP_KERNEL 0 +#define GFP_BUFFER 0 +#define __GFP_WAIT 0 + +#endif diff --git a/pfinet/glue-include/linux/param.h b/pfinet/glue-include/linux/param.h new file mode 100644 index 00000000..39efaf0d --- /dev/null +++ b/pfinet/glue-include/linux/param.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/personality.h b/pfinet/glue-include/linux/personality.h new file mode 100644 index 00000000..9e218435 --- /dev/null +++ b/pfinet/glue-include/linux/personality.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/poll.h b/pfinet/glue-include/linux/poll.h new file mode 100644 index 00000000..d608abf2 --- /dev/null +++ b/pfinet/glue-include/linux/poll.h @@ -0,0 +1,24 @@ +#ifndef _HACK_POLL_H_ +#define _HACK_POLL_H_ + +#include + +#define POLLIN SELECT_READ +#define POLLRDNORM SELECT_READ +#define POLLOUT SELECT_WRITE +#define POLLWRNORM SELECT_WRITE +#define POLLWRBAND SELECT_WRITE +#define POLLPRI SELECT_URG +#define POLLERR 0 +#define POLLHUP 0 + +typedef struct poll_table_struct { } poll_table; + +#include + +static inline void +poll_wait(struct file * filp, struct wait_queue ** wait_address, poll_table *p) +{ +} + +#endif diff --git a/pfinet/glue-include/linux/proc_fs.h b/pfinet/glue-include/linux/proc_fs.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/linux/sched.h b/pfinet/glue-include/linux/sched.h new file mode 100644 index 00000000..897a2df0 --- /dev/null +++ b/pfinet/glue-include/linux/sched.h @@ -0,0 +1,176 @@ +#ifndef _HACK_SCHED_H +#define _HACK_SCHED_H + +#include +#include +#include +#include +#include +#include +#include + +#include "mapped-time.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#if 0 +#include +#include + +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + + +#define jiffies (fetch_jiffies ()) + +#define current (¤t_contents) +extern struct task_struct current_contents; +struct task_struct +{ + uid_t pgrp, pid; + int flags; + int timeout; + int signal; + int blocked; + int state, policy; + int isroot; + char *comm; + struct wait_queue **next_wait; +}; + +static inline void +prepare_current (int isroot) +{ + current->signal = 0; + current->isroot = isroot; + /* All other members are constant zero and ignored. */ +} +#define become_task(user) prepare_current ((user)->isroot) +#define become_task_protid(protid) prepare_current ((protid)->isroot) + +#define signal_pending(current) ((current)->signal) + +/* FLAGS in task_struct's. */ +#define PF_EXITING 1 +/* STATE in task_struct's. */ +#define TASK_INTERRUPTIBLE 0 +#define TASK_RUNNING 0 +/* policy in task_struct's. */ +#define SCHED_YIELD 0 + +struct semaphore { }; + + +extern inline int +suser () +{ + return current->isroot; +}; + +extern inline int +capable(int cap) +{ + return current->isroot; +} + + +extern struct mutex global_lock; + +static inline void +interruptible_sleep_on (struct wait_queue **p) +{ + struct condition **condp = (void *) p, *c; + int isroot; + struct wait_queue **next_wait; + + c = *condp; + if (c == 0) + { + c = malloc (sizeof **condp); + assert (c); + condition_init (c); + *condp = c; + } + + isroot = current->isroot; /* This is our context that needs switched. */ + next_wait = current->next_wait; /* This too, for multiple schedule calls. */ + current->next_wait = 0; + if (hurd_condition_wait (c, &global_lock)) + current->signal = 1; /* We got cancelled, mark it for later. */ + current->isroot = isroot; /* Switch back to our context. */ + current->next_wait = next_wait; +} +#define sleep_on interruptible_sleep_on + +static inline void +wake_up_interruptible (struct wait_queue **p) +{ + struct condition **condp = (void *) p, *c = *condp; + if (c) + condition_broadcast (c); +} +#define wake_up wake_up_interruptible + + +static inline void +add_wait_queue(struct wait_queue ** p, struct wait_queue * wait) +{ + assert (current->next_wait == 0); + current->next_wait = p; +} + +static inline void +remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait) +{ + assert (current->next_wait == p); + current->next_wait = 0; +} + +static inline void +schedule (void) +{ + assert (current->next_wait); + interruptible_sleep_on (current->next_wait); +} + +static inline long +schedule_timeout (long timeout) +{ + /* XXX this is only ever called to do SO_LINGER, which we don't support */ + assert (!"schedule_timeout"); + return 0; +} + +#define MAX_SCHEDULE_TIMEOUT LONG_MAX + +/* This function is used only to send SIGPIPE to the current + task. In all such cases, EPIPE is returned anyhow. In the + Hurd, servers are not responsible for SIGPIPE; the library + does that itself upon receiving EPIPE. So we can just + NOP such calls. */ +extern inline int +send_sig (u_long signo, struct task_struct *task, int priv) +{ + assert (signo == SIGPIPE); + assert (task == current); + return 0; +} + + +#endif diff --git a/pfinet/glue-include/linux/slab.h b/pfinet/glue-include/linux/slab.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/linux/socket.h b/pfinet/glue-include/linux/socket.h new file mode 100644 index 00000000..12c73bfa --- /dev/null +++ b/pfinet/glue-include/linux/socket.h @@ -0,0 +1,138 @@ +#ifndef _HACK_SOCKET_H_ +#define _HACK_SOCKET_H_ + +#include +#include + +#include +#include +#include +#include + + +/* #define IP_MAX_MEMBERSHIPS 10 */ + +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 + +#define SOPRI_INTERACTIVE 0 +#define SOPRI_NORMAL 1 +#define SOPRI_BACKGROUND 2 + +#define SOL_IP IPPROTO_IP +#define SOL_TCP IPPROTO_TCP +#define SOL_RAW IPPROTO_RAW + +/* IP options */ +#define IP_PKTINFO 190 +#define IP_PKTOPTIONS 191 +#define IP_MTU_DISCOVER 192 +#define IP_RECVERR 193 +#define IP_RECVTTL 194 +#define IP_RECVTOS 195 +#define IP_MTU 196 +#define IP_ROUTER_ALERT 197 + + +/* TCP options */ +#define TCP_NODELAY 1 +#define TCP_MAXSEG 2 +#define TCP_CORK 3 + +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 + +#define SO_PASSCRED 190 +#define SO_PEERCRED 191 +#define SO_BSDCOMPAT 192 + +/* Maximum queue length specifiable by listen. */ +#define SOMAXCONN 128 + +/* XXX */ +#define msg_control msg_accrights +#define msg_controllen msg_accrightslen +struct cmsghdr { int cmsg_garbage; }; +#define cmsg_len cmsg_garbage +#define cmsg_type cmsg_garbage +#define cmsg_level cmsg_garbage +static inline int +put_cmsg(struct msghdr *msg, int level, int type, int len, void *data) +{ return 0; } +#define CMSG_FIRSTHDR(msg) (0) +#define CMSG_NXTHDR(msg, cmsg) (0) +#define CMSG_DATA(cmsg) (0) +#define CMSG_ALIGN(size) (0) +#define CMSG_LEN(size) (0) + + +#define MSG_NOSIGNAL 0 +#define MSG_ERRQUEUE 0 + +/* There is no SOCK_PACKET, it is a bad bad thing. This chicanery is + because the one use of it is a comparison against a `short int' value; + using a value outside the range of that type ensures that the comparison + will always fail, and in fact it and the dead code will get optimized + out entirely at compile time. */ +#define SOCK_PACKET ((int)((uint32_t)USHRT_MAX) * 2) +#define PF_PACKET 0 + +#ifndef UIO_MAXIOV +#define UIO_MAXIOV 4 /* 1 would do */ +#endif + + +struct ucred { + pid_t pid; + uid_t uid; + gid_t gid; +}; + + +extern inline int +memcpy_fromiovecend (unsigned char *kdata, struct iovec *iov, + int offset, int len) +{ + assert (offset + len <= iov->iov_len); + memcpy (kdata, iov->iov_base + offset, len); + return 0; +} +extern inline int +memcpy_fromiovec (unsigned char *kdata, struct iovec *iov, int len) +{ + assert (len <= iov->iov_len); + memcpy (kdata, iov->iov_base, len); + return 0; +} +extern inline int +memcpy_toiovec (struct iovec *iov, unsigned char *kdata, int len) +{ + assert (len <= iov->iov_len); + memcpy (iov->iov_base, kdata, len); + return 0; +} +extern inline void +memcpy_tokerneliovec (struct iovec *iov, unsigned char *kdata, int len) +{ + assert (len <= iov->iov_len); + memcpy (iov->iov_base, kdata, len); +} + +extern int csum_partial_copy_fromiovecend(unsigned char *kdata, + struct iovec *iov, + int offset, + unsigned int len, int *csump); + +static inline int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr) +{ + abort (); + return 0; +} +#if 0 +extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); +extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen); +#endif + + +#endif diff --git a/pfinet/glue-include/linux/sockios.h b/pfinet/glue-include/linux/sockios.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/linux/stat.h b/pfinet/glue-include/linux/stat.h new file mode 100644 index 00000000..5165069b --- /dev/null +++ b/pfinet/glue-include/linux/stat.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/string.h b/pfinet/glue-include/linux/string.h new file mode 100644 index 00000000..3b2f5900 --- /dev/null +++ b/pfinet/glue-include/linux/string.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/termios.h b/pfinet/glue-include/linux/termios.h new file mode 100644 index 00000000..9e269565 --- /dev/null +++ b/pfinet/glue-include/linux/termios.h @@ -0,0 +1 @@ +#include diff --git a/pfinet/glue-include/linux/time.h b/pfinet/glue-include/linux/time.h new file mode 100644 index 00000000..4973c4ab --- /dev/null +++ b/pfinet/glue-include/linux/time.h @@ -0,0 +1,10 @@ +#ifndef _HACK_TIME_H_ +#define _HACK_TIME_H_ + +#include +#include "mapped-time.h" + +#define do_gettimeofday(tp) maptime_read (mapped_time, (tp)) +#define get_fast_time(tp) maptime_read (mapped_time, (tp)) + +#endif diff --git a/pfinet/glue-include/linux/timer.h b/pfinet/glue-include/linux/timer.h new file mode 100644 index 00000000..cc8dec80 --- /dev/null +++ b/pfinet/glue-include/linux/timer.h @@ -0,0 +1,36 @@ +#ifndef _HACK_TIMER_H_ +#define _HACK_TIMER_H_ + +#include + +enum tstate +{ + TIMER_INACTIVE, + TIMER_STARTING, + TIMER_STARTED, + TIMER_EXPIRED, + TIMER_FUNCTION_RUNNING, +}; + +struct timer_list +{ + struct timer_list *next, **prev; /* things like to test "T->prev != NULL" */ + unsigned long expires; + unsigned long data; + void (*function)(unsigned long); +}; + +void add_timer (struct timer_list *); +int del_timer (struct timer_list *); +void mod_timer (struct timer_list *, unsigned long); +void init_timer (struct timer_list *); + + +#define time_after(a,b) ((long)(b) - (long)(a) < 0) +#define time_before(a,b) time_after(b,a) + +#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0) +#define time_before_eq(a,b) time_after_eq(b,a) + + +#endif diff --git a/pfinet/glue-include/linux/timex.h b/pfinet/glue-include/linux/timex.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/linux/types.h b/pfinet/glue-include/linux/types.h new file mode 100644 index 00000000..604b8b14 --- /dev/null +++ b/pfinet/glue-include/linux/types.h @@ -0,0 +1,31 @@ +#ifndef _HACK_TYPES_H +#define _HACK_TYPES_H + +#include +#include +#include +#include +#include + +#define __u8 uint8_t +#define __u16 uint16_t +#define __u32 uint32_t +#define __u64 uint64_t +#define __s8 int8_t +#define __s16 int16_t +#define __s32 int32_t +#define __s64 int64_t +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t +#define s8 int8_t +#define s16 int16_t +#define s32 int32_t +#define s64 int64_t + +#include +#include +#include + +#endif diff --git a/pfinet/glue-include/linux/un.h b/pfinet/glue-include/linux/un.h new file mode 100644 index 00000000..e69de29b diff --git a/pfinet/glue-include/linux/version.h b/pfinet/glue-include/linux/version.h new file mode 100644 index 00000000..3a49a481 --- /dev/null +++ b/pfinet/glue-include/linux/version.h @@ -0,0 +1,3 @@ +#define UTS_RELEASE "2.1.12" +#define LINUX_VERSION_CODE KERNEL_VERSION(2,1,12) +#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) diff --git a/pfinet/glue-include/linux/wait.h b/pfinet/glue-include/linux/wait.h new file mode 100644 index 00000000..7ee962dc --- /dev/null +++ b/pfinet/glue-include/linux/wait.h @@ -0,0 +1,32 @@ +#ifndef _HACK_WAIT_H_ +#define _HACK_WAIT_H_ + +#include + +/* This data structure actually represents one waiter on a wait queue, + and waiters always expect to initialize it with { current, NULL }. + The actual wait queue is a `struct wait_queue *' stored somewhere. + We ignore these structures provided by the waiters entirely. + In the `struct wait_queue *' that is the "head of the wait queue" slot, + we actually store a `struct condition *' pointing to malloc'd storage. */ + +struct wait_queue +{ + struct task_struct *task; /* current */ + struct wait_queue *next; /* NULL */ +}; + + +struct select_table_elt +{ + struct condition *dependent_condition; + struct select_table_elt *next; +}; + +typedef struct select_table_struct +{ + struct condition master_condition; + struct select_table_elt *head; +} select_table; + +#endif diff --git a/pfinet/io-ops.c b/pfinet/io-ops.c index b6831c31..c4cfc253 100644 --- a/pfinet/io-ops.c +++ b/pfinet/io-ops.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1995,96,97,98,99,2000 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -19,10 +19,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include "pfinet.h" + +#include +#include +#include +#include + #include "io_S.h" #include -#include -#include #include #include #include @@ -37,15 +41,19 @@ S_io_write (struct sock_user *user, mach_msg_type_number_t *amount) { error_t err; + struct iovec iov = { data, datalen }; + struct msghdr m = { msg_name: 0, msg_namelen: 0, msg_flags: 0, + msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 }; if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); - err = (*user->sock->ops->write) (user->sock, data, datalen, - user->sock->userflags); - mutex_unlock (&global_lock); + if (user->sock->flags & O_NONBLOCK) + m.msg_flags |= MSG_DONTWAIT; + err = (*user->sock->ops->sendmsg) (user->sock, &m, datalen, 0); + __mutex_unlock (&global_lock); if (err < 0) err = -err; @@ -67,6 +75,9 @@ S_io_read (struct sock_user *user, { error_t err; int alloced = 0; + struct iovec iov; + struct msghdr m = { msg_name: 0, msg_namelen: 0, msg_flags: 0, + msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 }; if (!user) return EOPNOTSUPP; @@ -79,11 +90,16 @@ S_io_read (struct sock_user *user, alloced = 1; } - mutex_lock (&global_lock); + iov.iov_base = *data; + iov.iov_len = amount; + + __mutex_lock (&global_lock); become_task (user); - err = (*user->sock->ops->read) (user->sock, *data, amount, - user->sock->userflags); - mutex_unlock (&global_lock); + err = (*user->sock->ops->recvmsg) (user->sock, &m, amount, + ((user->sock->flags & O_NONBLOCK) + ? MSG_DONTWAIT : 0), + 0); + __mutex_unlock (&global_lock); if (err < 0) err = -err; @@ -117,13 +133,13 @@ S_io_readable (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); /* We need to avoid calling the Linux ioctl routines, so here is a rather ugly break of modularity. */ - sk = (struct sock *) user->sock->data; + sk = user->sock->sk; err = 0; /* Linux's af_inet.c ioctl routine just calls the protocol-specific @@ -134,15 +150,7 @@ S_io_readable (struct sock_user *user, { case SOCK_STREAM: case SOCK_SEQPACKET: - /* These guts are copied from tcp.c:tcp_ioctl. */ - if (sk->state == TCP_LISTEN) - err = EINVAL; - else - { - sk->inuse = 1; - *amount = tcp_readable (sk); - release_sock (sk); - } + err = tcp_tiocinq (sk, amount); break; case SOCK_DGRAM: @@ -161,7 +169,7 @@ S_io_readable (struct sock_user *user, break; } - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return err; } @@ -172,12 +180,12 @@ S_io_set_all_openmodes (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); if (bits & O_NONBLOCK) - user->sock->userflags |= O_NONBLOCK; + user->sock->flags |= O_NONBLOCK; else - user->sock->userflags &= ~O_NONBLOCK; - mutex_unlock (&global_lock); + user->sock->flags &= ~O_NONBLOCK; + __mutex_unlock (&global_lock); return 0; } @@ -190,18 +198,18 @@ S_io_get_openmodes (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); - sk = user->sock->data; + __mutex_lock (&global_lock); + sk = user->sock->sk; *bits = 0; if (!(sk->shutdown & SEND_SHUTDOWN)) *bits |= O_WRITE; if (!(sk->shutdown & RCV_SHUTDOWN)) *bits |= O_READ; - if (user->sock->userflags & O_NONBLOCK) + if (user->sock->flags & O_NONBLOCK) *bits |= O_NONBLOCK; - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return 0; } @@ -212,10 +220,10 @@ S_io_set_some_openmodes (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); if (bits & O_NONBLOCK) - user->sock->userflags |= O_NONBLOCK; - mutex_unlock (&global_lock); + user->sock->flags |= O_NONBLOCK; + __mutex_unlock (&global_lock); return 0; } @@ -226,114 +234,62 @@ S_io_clear_some_openmodes (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); if (bits & O_NONBLOCK) - user->sock->userflags &= ~O_NONBLOCK; - mutex_unlock (&global_lock); + user->sock->flags &= ~O_NONBLOCK; + __mutex_unlock (&global_lock); return 0; } error_t S_io_select (struct sock_user *user, - mach_port_t reply, mach_msg_type_name_t reply_type, + mach_port_t reply, + mach_msg_type_name_t reply_type, int *select_type) { - int avail = 0; - int cancel = 0; - int requested_notify = 0; - select_table table; - struct select_table_elt *elt, *nxt; + const int want = *select_type; + int avail; if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); /* In Linux, this means (supposedly) that I/O will never be possible. That's a lose, so prevent it from happening. */ - assert (user->sock->ops->select); - - /* The select function returns one if the specified I/O type is - immediately possible. If it returns zero, then it is not - immediately possible, and it has called select_wait. Eventually - it will wakeup the wait queue specified in the select_wait call; - at that point we should retry the call. */ + assert (user->sock->ops->poll); - for (;;) + avail = (*user->sock->ops->poll) ((void *) 0xdeadbeef, + user->sock, + (void *) 0xdeadbead); + if ((avail & want) == 0) { - condition_init (&table.master_condition); - table.head = 0; - - if (*select_type & SELECT_READ) - avail |= ((*user->sock->ops->select) (user->sock, SEL_IN, &table) - ? SELECT_READ : 0); - if (*select_type & SELECT_WRITE) - avail |= ((*user->sock->ops->select) (user->sock, SEL_OUT, &table) - ? SELECT_WRITE : 0); - if (*select_type & SELECT_URG) - avail |= ((*user->sock->ops->select) (user->sock, SEL_EX, &table) - ? SELECT_URG : 0); - - if (!avail) + ports_interrupt_self_on_notification (user, reply, + MACH_NOTIFY_DEAD_NAME); + + do { - if (! requested_notify) + /* Block until we are woken or cancelled. */ + interruptible_sleep_on (user->sock->sk->sleep); + if (signal_pending (current)) /* This means we were cancelled. */ { - ports_interrupt_self_on_notification (user, reply, - MACH_NOTIFY_DEAD_NAME); - requested_notify = 1; + __mutex_unlock (&global_lock); + return EINTR; } - cancel = hurd_condition_wait (&table.master_condition, &global_lock); - } - - /* Drop the conditions implications and structures allocated in the - select table. */ - for (elt = table.head; elt; elt = nxt) - { - condition_unimplies (elt->dependent_condition, - &table.master_condition); - nxt = elt->next; - free (elt); - } - - if (avail) - { - mutex_unlock (&global_lock); - *select_type = avail; - return 0; - } - - if (cancel) - { - mutex_unlock (&global_lock); - mach_port_deallocate (mach_task_self (), reply); - return EINTR; + avail = (*user->sock->ops->poll) ((void *) 0xdeadbeef, + user->sock, + (void *) 0xdeadbead); } + while ((avail & want) == 0); } -} -/* Establish that the condition in WAIT_ADDRESS should imply - the condition in P. Also, add us to the queue in P so - that the relation can be undone at the proper time. */ -void -select_wait (struct wait_queue **wait_address, select_table *p) -{ - struct select_table_elt *elt; + /* We got something. */ + *select_type = avail; - /* tcp.c happens to use an uninitalized wait queue; - so this special hack is for that. */ - if (*wait_address == 0) - { - *wait_address = malloc (sizeof (struct wait_queue)); - condition_init (&(*wait_address)->c); - } + __mutex_unlock (&global_lock); - elt = malloc (sizeof (struct select_table_elt)); - elt->dependent_condition = &(*wait_address)->c; - elt->next = p->head; - p->head = elt; - - condition_implies (elt->dependent_condition, &p->master_condition); + return 0; } error_t @@ -349,7 +305,9 @@ S_io_stat (struct sock_user *user, st->st_fsid = getpid (); st->st_ino = (ino_t) user->sock; /* why not? */ + st->st_mode = S_IFSOCK | ACCESSPERMS; st->st_blksize = 512; /* ???? */ + return 0; } @@ -375,7 +333,7 @@ S_io_reauthenticate (struct sock_user *user, aux_uids = aubuf; aux_gids = agbuf; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); newuser = make_sock_user (user->sock, 0, 1); auth = getauth (); @@ -408,7 +366,7 @@ S_io_reauthenticate (struct sock_user *user, mach_port_move_member (mach_task_self (), newuser->pi.port_right, pfinet_bucket->portset); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); ports_port_deref (newuser); @@ -440,7 +398,7 @@ S_io_restrict_auth (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); isroot = 0; if (user->isroot) @@ -452,7 +410,7 @@ S_io_restrict_auth (struct sock_user *user, *newobject = ports_get_right (newuser); *newobject_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (newuser); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return 0; } @@ -465,12 +423,12 @@ S_io_duplicate (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); newuser = make_sock_user (user->sock, user->isroot, 0); *newobject = ports_get_right (newuser); *newobject_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (newuser); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return 0; } @@ -487,14 +445,14 @@ S_io_identity (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); if (user->sock->identity == MACH_PORT_NULL) { err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &user->sock->identity); if (err) { - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return err; } } @@ -505,7 +463,7 @@ S_io_identity (struct sock_user *user, *fsystype = MACH_MSG_TYPE_MAKE_SEND; *fileno = (ino_t) user->sock; /* matches S_io_stat above */ - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return 0; } diff --git a/pfinet/kmem_cache.c b/pfinet/kmem_cache.c new file mode 100644 index 00000000..8c73c9bf --- /dev/null +++ b/pfinet/kmem_cache.c @@ -0,0 +1,88 @@ +/* Hack replacement for Linux's kmem_cache_t allocator + Copyright (C) 2000 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +/* Hack replacement for Linux's kmem_cache_t allocator, using plain malloc + and cthreads locking. The locking here is probably unnecessary. */ + +#include +#include + +struct kmem_cache_s +{ + struct mutex lock; + + void *freelist; + size_t item_size; + + void (*ctor) (void *, kmem_cache_t *, unsigned long); + void (*dtor) (void *, kmem_cache_t *, unsigned long); +}; + +kmem_cache_t * +kmem_cache_create (const char *name, size_t item_size, + size_t something, unsigned long flags, + void (*ctor) (void *, kmem_cache_t *, unsigned long), + void (*dtor) (void *, kmem_cache_t *, unsigned long)) +{ + kmem_cache_t *new = malloc (sizeof *new); + if (!new) + return 0; + mutex_init (&new->lock); + new->freelist = 0; + new->item_size = item_size; + new->ctor = ctor; + new->dtor = dtor; + + return new; +} + + +void * +kmem_cache_alloc (kmem_cache_t *cache, int flags) +{ + void *p; + + __mutex_lock (&cache->lock); + p = cache->freelist; + if (p != 0) { + cache->freelist = *(void **)(p + cache->item_size); + __mutex_unlock (&cache->lock); + return p; + } + __mutex_unlock (&cache->lock); + + p = malloc (cache->item_size + sizeof (void *)); + if (p && cache->ctor) + (*cache->ctor) (p, cache, flags); + return p; +} + + +void +kmem_cache_free (kmem_cache_t *cache, void *p) +{ + void **const nextp = (void **) (p + cache->item_size); + + __mutex_lock (&cache->lock); + *nextp = cache->freelist; + cache->freelist = p; + __mutex_unlock (&cache->lock); + + /* XXX eventually destroy some... */ +} diff --git a/pfinet/linux-inet/af_inet.c b/pfinet/linux-inet/af_inet.c deleted file mode 100644 index d20c8bfb..00000000 --- a/pfinet/linux-inet/af_inet.c +++ /dev/null @@ -1,1578 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * AF_INET protocol family socket handler. - * - * Version: @(#)af_inet.c (from sock.c) 1.0.17 06/02/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Florian La Roche, - * Alan Cox, - * - * Changes (see also sock.c) - * - * A.N.Kuznetsov : Socket death error in accept(). - * John Richardson : Fix non blocking error in connect() - * so sockets that fail to connect - * don't return -EINPROGRESS. - * Alan Cox : Asynchronous I/O support - * Alan Cox : Keep correct socket pointer on sock structures - * when accept() ed - * Alan Cox : Semantics of SO_LINGER aren't state moved - * to close when you look carefully. With - * this fixed and the accept bug fixed - * some RPC stuff seems happier. - * Niibe Yutaka : 4.4BSD style write async I/O - * Alan Cox, - * Tony Gale : Fixed reuse semantics. - * Alan Cox : bind() shouldn't abort existing but dead - * sockets. Stops FTP netin:.. I hope. - * Alan Cox : bind() works correctly for RAW sockets. Note - * that FreeBSD at least is broken in this respect - * so be careful with compatibility tests... - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include "ip.h" -#include "protocol.h" -#include "arp.h" -#include "rarp.h" -#include "route.h" -#include "tcp.h" -#include "udp.h" -#include -#include "sock.h" -#include "raw.h" -#include "icmp.h" - -#define min(a,b) ((a)<(b)?(a):(b)) - -extern struct proto packet_prot; - - -/* - * See if a socket number is in use. - */ - -static int sk_inuse(struct proto *prot, int num) -{ - struct sock *sk; - - for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )]; - sk != NULL; sk=sk->next) - { - if (sk->num == num) - return(1); - } - return(0); -} - - -/* - * Pick a new socket number - */ - -unsigned short get_new_socknum(struct proto *prot, unsigned short base) -{ - static int start=0; - - /* - * Used to cycle through the port numbers so the - * chances of a confused connection drop. - */ - - int i, j; - int best = 0; - int size = 32767; /* a big num. */ - struct sock *sk; - - if (base == 0) - base = PROT_SOCK+1+(start % 1024); - if (base <= PROT_SOCK) - { - base += PROT_SOCK+(start % 1024); - } - - /* Now look through the entire array and try to find an empty ptr. */ - for(i=0; i < SOCK_ARRAY_SIZE; i++) - { - j = 0; - sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)]; - while(sk != NULL) - { - sk = sk->next; - j++; - } - if (j == 0) - { - start =(i+1+start )%1024; - return(i+base+1); - } - if (j < size) - { - best = i; - size = j; - } - } - - /* Now make sure the one we want is not in use. */ - - while(sk_inuse(prot, base +best+1)) - { - best += SOCK_ARRAY_SIZE; - } - return(best+base+1); -} - -/* - * Add a socket into the socket tables by number. - */ - -void put_sock(unsigned short num, struct sock *sk) -{ - struct sock *sk1; - struct sock *sk2; - int mask; - unsigned long flags; - - sk->num = num; - sk->next = NULL; - num = num &(SOCK_ARRAY_SIZE -1); - - /* We can't have an interrupt re-enter here. */ - save_flags(flags); - cli(); - - sk->prot->inuse += 1; - if (sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; - - if (sk->prot->sock_array[num] == NULL) - { - sk->prot->sock_array[num] = sk; - restore_flags(flags); - return; - } - restore_flags(flags); - for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) - { - if ((mask & sk->saddr) && - (mask & sk->saddr) != (mask & 0xffffffff)) - { - mask = mask << 8; - break; - } - } - cli(); - sk1 = sk->prot->sock_array[num]; - for(sk2 = sk1; sk2 != NULL; sk2=sk2->next) - { - if (!(sk2->saddr & mask)) - { - if (sk2 == sk1) - { - sk->next = sk->prot->sock_array[num]; - sk->prot->sock_array[num] = sk; - sti(); - return; - } - sk->next = sk2; - sk1->next= sk; - sti(); - return; - } - sk1 = sk2; - } - - /* Goes at the end. */ - sk->next = NULL; - sk1->next = sk; - sti(); -} - -/* - * Remove a socket from the socket tables. - */ - -static void remove_sock(struct sock *sk1) -{ - struct sock *sk2; - unsigned long flags; - - if (!sk1->prot) - { - printk("sock.c: remove_sock: sk1->prot == NULL\n"); - return; - } - - /* We can't have this changing out from under us. */ - save_flags(flags); - cli(); - sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)]; - if (sk2 == sk1) - { - sk1->prot->inuse -= 1; - sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next; - restore_flags(flags); - return; - } - - while(sk2 && sk2->next != sk1) - { - sk2 = sk2->next; - } - - if (sk2) - { - sk1->prot->inuse -= 1; - sk2->next = sk1->next; - restore_flags(flags); - return; - } - restore_flags(flags); -} - -/* - * Destroy an AF_INET socket - */ - -void destroy_sock(struct sock *sk) -{ - struct sk_buff *skb; - - sk->inuse = 1; /* just to be safe. */ - - /* In case it's sleeping somewhere. */ - if (!sk->dead) - sk->write_space(sk); - - remove_sock(sk); - - /* Now we can no longer get new packets. */ - delete_timer(sk); - /* Nor send them */ - del_timer(&sk->retransmit_timer); - - while ((skb = tcp_dequeue_partial(sk)) != NULL) { - IS_SKB(skb); - kfree_skb(skb, FREE_WRITE); - } - - /* Cleanup up the write buffer. */ - while((skb = skb_dequeue(&sk->write_queue)) != NULL) { - IS_SKB(skb); - kfree_skb(skb, FREE_WRITE); - } - - /* - * Don't discard received data until the user side kills its - * half of the socket. - */ - - if (sk->dead) - { - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) - { - /* - * This will take care of closing sockets that were - * listening and didn't accept everything. - */ - if (skb->sk != NULL && skb->sk != sk) - { - IS_SKB(skb); - skb->sk->dead = 1; - skb->sk->prot->close(skb->sk, 0); - } - IS_SKB(skb); - kfree_skb(skb, FREE_READ); - } - } - - /* Now we need to clean up the send head. */ - cli(); - for(skb = sk->send_head; skb != NULL; ) - { - struct sk_buff *skb2; - - /* - * We need to remove skb from the transmit queue, - * or maybe the arp queue. - */ - if (skb->next && skb->prev) { -/* printk("destroy_sock: unlinked skb\n");*/ - IS_SKB(skb); - skb_unlink(skb); - } - skb->dev = NULL; - skb2 = skb->link3; - kfree_skb(skb, FREE_WRITE); - skb = skb2; - } - sk->send_head = NULL; - sti(); - - /* And now the backlog. */ - while((skb=skb_dequeue(&sk->back_log))!=NULL) - { - /* this should never happen. */ -/* printk("cleaning back_log\n");*/ - kfree_skb(skb, FREE_READ); - } - - /* Now if it has a half accepted/ closed socket. */ - if (sk->pair) - { - sk->pair->dead = 1; - sk->pair->prot->close(sk->pair, 0); - sk->pair = NULL; - } - - /* - * Now if everything is gone we can free the socket - * structure, otherwise we need to keep it around until - * everything is gone. - */ - - if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) - { - kfree_s((void *)sk,sizeof(*sk)); - } - else - { - /* this should never happen. */ - /* actually it can if an ack has just been sent. */ - sk->destroy = 1; - sk->ack_backlog = 0; - sk->inuse = 0; - reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME); - } -} - -/* - * The routines beyond this point handle the behaviour of an AF_INET - * socket object. Mostly it punts to the subprotocols of IP to do - * the work. - */ - -static int inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - - switch(cmd) - { - case F_SETOWN: - /* - * This is a little restrictive, but it's the only - * way to make sure that you can't send a sigurg to - * another process. - */ - if (!suser() && current->pgrp != -arg && - current->pid != arg) return(-EPERM); - sk->proc = arg; - return(0); - case F_GETOWN: - return(sk->proc); - default: - return(-EINVAL); - } -} - -/* - * Set socket options on an inet socket. - */ - -static int inet_setsockopt(struct socket *sock, int level, int optname, - char *optval, int optlen) -{ - struct sock *sk = (struct sock *) sock->data; - if (level == SOL_SOCKET) - return sock_setsockopt(sk,level,optname,optval,optlen); - if (sk->prot->setsockopt==NULL) - return(-EOPNOTSUPP); - else - return sk->prot->setsockopt(sk,level,optname,optval,optlen); -} - -/* - * Get a socket option on an AF_INET socket. - */ - -static int inet_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) -{ - struct sock *sk = (struct sock *) sock->data; - if (level == SOL_SOCKET) - return sock_getsockopt(sk,level,optname,optval,optlen); - if(sk->prot->getsockopt==NULL) - return(-EOPNOTSUPP); - else - return sk->prot->getsockopt(sk,level,optname,optval,optlen); -} - -/* - * Automatically bind an unbound socket. - */ - -static int inet_autobind(struct sock *sk) -{ - /* We may need to bind the socket. */ - if (sk->num == 0) - { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) - return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - return 0; -} - -/* - * Move a socket into listening state. - */ - -static int inet_listen(struct socket *sock, int backlog) -{ - struct sock *sk = (struct sock *) sock->data; - - if(inet_autobind(sk)!=0) - return -EAGAIN; - - /* We might as well re use these. */ - /* - * note that the backlog is "unsigned char", so truncate it - * somewhere. We might as well truncate it to what everybody - * else does.. - */ - if (backlog > 5) - backlog = 5; - sk->max_ack_backlog = backlog; - if (sk->state != TCP_LISTEN) - { - sk->ack_backlog = 0; - sk->state = TCP_LISTEN; - } - return(0); -} - -/* - * Default callbacks for user INET sockets. These just wake up - * the user owning the socket. - */ - -static void def_callback1(struct sock *sk) -{ - if(!sk->dead) - wake_up_interruptible(sk->sleep); -} - -static void def_callback2(struct sock *sk,int len) -{ - if(!sk->dead) - { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 1); - } -} - -static void def_callback3(struct sock *sk) -{ - if(!sk->dead) - { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 2); - } -} - -/* - * Create an inet socket. - * - * FIXME: Gcc would generate much better code if we set the parameters - * up in in-memory structure order. Gcc68K even more so - */ - -static int inet_create(struct socket *sock, int protocol) -{ - struct sock *sk; - struct proto *prot; - int err; - - sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL); - if (sk == NULL) - return(-ENOBUFS); - sk->num = 0; - sk->reuse = 0; - switch(sock->type) - { - case SOCK_STREAM: - case SOCK_SEQPACKET: - if (protocol && protocol != IPPROTO_TCP) - { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - protocol = IPPROTO_TCP; - sk->no_check = TCP_NO_CHECK; - prot = &tcp_prot; - break; - - case SOCK_DGRAM: - if (protocol && protocol != IPPROTO_UDP) - { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - protocol = IPPROTO_UDP; - sk->no_check = UDP_NO_CHECK; - prot=&udp_prot; - break; - - case SOCK_RAW: - if (!suser()) - { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPERM); - } - if (!protocol) - { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - prot = &raw_prot; - sk->reuse = 1; - sk->no_check = 0; /* - * Doesn't matter no checksum is - * performed anyway. - */ - sk->num = protocol; - break; - -#ifndef _HURD_ - case SOCK_PACKET: - if (!suser()) - { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPERM); - } - if (!protocol) - { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - prot = &packet_prot; - sk->reuse = 1; - sk->no_check = 0; /* Doesn't matter no checksum is - * performed anyway. - */ - sk->num = protocol; - break; -#endif - - default: - kfree_s((void *)sk, sizeof(*sk)); - return(-ESOCKTNOSUPPORT); - } - sk->socket = sock; -#ifdef CONFIG_TCP_NAGLE_OFF - sk->nonagle = 1; -#else - sk->nonagle = 0; -#endif - sk->type = sock->type; - sk->stamp.tv_sec=0; - sk->protocol = protocol; - sk->wmem_alloc = 0; - sk->rmem_alloc = 0; - sk->sndbuf = SK_WMEM_MAX; - sk->rcvbuf = SK_RMEM_MAX; - sk->pair = NULL; - sk->opt = NULL; - sk->write_seq = 0; - sk->acked_seq = 0; - sk->copied_seq = 0; - sk->fin_seq = 0; - sk->urg_seq = 0; - sk->urg_data = 0; - sk->proc = 0; - sk->rtt = 0; /*TCP_WRITE_TIME << 3;*/ - sk->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/ - sk->mdev = 0; - sk->backoff = 0; - sk->packets_out = 0; - sk->cong_window = 1; /* start with only sending one packet at a time. */ - sk->cong_count = 0; - sk->ssthresh = 0; - sk->max_window = 0; - sk->urginline = 0; - sk->intr = 0; - sk->linger = 0; - sk->destroy = 0; - sk->priority = 1; - sk->shutdown = 0; - sk->keepopen = 0; - sk->zapped = 0; - sk->done = 0; - sk->ack_backlog = 0; - sk->window = 0; - sk->bytes_rcv = 0; - sk->state = TCP_CLOSE; - sk->dead = 0; - sk->ack_timed = 0; - sk->partial = NULL; - sk->user_mss = 0; - sk->debug = 0; - - /* this is how many unacked bytes we will accept for this socket. */ - sk->max_unacked = 2048; /* needs to be at most 2 full packets. */ - - /* how many packets we should send before forcing an ack. - if this is set to zero it is the same as sk->delay_acks = 0 */ - sk->max_ack_backlog = 0; - sk->inuse = 0; - sk->delay_acks = 0; - skb_queue_head_init(&sk->write_queue); - skb_queue_head_init(&sk->receive_queue); - sk->mtu = 576; - sk->prot = prot; - sk->sleep = sock->wait; - sk->daddr = 0; - sk->saddr = 0 /* ip_my_addr() */; - sk->err = 0; - sk->next = NULL; - sk->pair = NULL; - sk->send_tail = NULL; - sk->send_head = NULL; - sk->timeout = 0; - sk->broadcast = 0; - sk->localroute = 0; - init_timer(&sk->timer); - init_timer(&sk->retransmit_timer); - sk->timer.data = (unsigned long)sk; - sk->timer.function = &net_timer; - skb_queue_head_init(&sk->back_log); - sk->blog = 0; - sock->data =(void *) sk; - sk->dummy_th.doff = sizeof(sk->dummy_th)/4; - sk->dummy_th.res1=0; - sk->dummy_th.res2=0; - sk->dummy_th.urg_ptr = 0; - sk->dummy_th.fin = 0; - sk->dummy_th.syn = 0; - sk->dummy_th.rst = 0; - sk->dummy_th.psh = 0; - sk->dummy_th.ack = 0; - sk->dummy_th.urg = 0; - sk->dummy_th.dest = 0; - sk->ip_tos=0; - sk->ip_ttl=64; -#ifdef CONFIG_IP_MULTICAST - sk->ip_mc_loop=1; - sk->ip_mc_ttl=1; - *sk->ip_mc_name=0; - sk->ip_mc_list=NULL; -#endif - - sk->state_change = def_callback1; - sk->data_ready = def_callback2; - sk->write_space = def_callback3; - sk->error_report = def_callback1; - - if (sk->num) - { - /* - * It assumes that any protocol which allows - * the user to assign a number at socket - * creation time automatically - * shares. - */ - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - - if (sk->prot->init) - { - err = sk->prot->init(sk); - if (err != 0) - { - destroy_sock(sk); - return(err); - } - } - return(0); -} - - -/* - * Duplicate a socket. - */ - -static int inet_dup(struct socket *newsock, struct socket *oldsock) -{ - return(inet_create(newsock,((struct sock *)(oldsock->data))->protocol)); -} - -/* - * Return 1 if we still have things to send in our buffers. - */ -static inline int closing(struct sock * sk) -{ - switch (sk->state) { - case TCP_FIN_WAIT1: - case TCP_CLOSING: - case TCP_LAST_ACK: - return 1; - } - return 0; -} - - -/* - * The peer socket should always be NULL (or else). When we call this - * function we are destroying the object and from then on nobody - * should refer to it. - */ - -static int inet_release(struct socket *sock, struct socket *peer) -{ - struct sock *sk = (struct sock *) sock->data; - if (sk == NULL) - return(0); - - sk->state_change(sk); - - /* Start closing the connection. This may take a while. */ - -#ifdef CONFIG_IP_MULTICAST - /* Applications forget to leave groups before exiting */ - ip_mc_drop_socket(sk); -#endif - /* - * If linger is set, we don't return until the close - * is complete. Other wise we return immediately. The - * actually closing is done the same either way. - * - * If the close is due to the process exiting, we never - * linger.. - */ - - if (sk->linger == 0 || (current->flags & PF_EXITING)) - { - sk->prot->close(sk,0); - sk->dead = 1; - } - else - { - sk->prot->close(sk, 0); - cli(); - if (sk->lingertime) - current->timeout = jiffies + HZ*sk->lingertime; - while(closing(sk) && current->timeout>0) - { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) - { - break; -#if 0 - /* not working now - closes can't be restarted */ - sti(); - current->timeout=0; - return(-ERESTARTSYS); -#endif - } - } - current->timeout=0; - sti(); - sk->dead = 1; - } - sk->inuse = 1; - - /* This will destroy it. */ - release_sock(sk); - sock->data = NULL; - sk->socket = NULL; - return(0); -} - - -/* this needs to be changed to disallow - the rebinding of sockets. What error - should it return? */ - -static int inet_bind(struct socket *sock, struct sockaddr *uaddr, - int addr_len) -{ - struct sockaddr_in *addr=(struct sockaddr_in *)uaddr; - struct sock *sk=(struct sock *)sock->data, *sk2; - unsigned short snum = 0 /* Stoopid compiler.. this IS ok */; - int chk_addr_ret; - - /* check this error. */ - if (sk->state != TCP_CLOSE) - return(-EIO); - if(addr_lentype != SOCK_RAW) - { - if (sk->num != 0) - return(-EINVAL); - - snum = ntohs(addr->sin_port); - - /* - * We can't just leave the socket bound wherever it is, it might - * be bound to a privileged port. However, since there seems to - * be a bug here, we will leave it if the port is not privileged. - */ - if (snum == 0) - { - snum = get_new_socknum(sk->prot, 0); - } - if (snum < PROT_SOCK && !suser()) - return(-EACCES); - } - - chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr); - if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST) - return(-EADDRNOTAVAIL); /* Source address MUST be ours! */ - - if (chk_addr_ret || addr->sin_addr.s_addr == 0) - sk->saddr = addr->sin_addr.s_addr; - - if(sock->type != SOCK_RAW) - { - /* Make sure we are allowed to bind here. */ - cli(); - for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)]; - sk2 != NULL; sk2 = sk2->next) - { - /* should be below! */ - if (sk2->num != snum) - continue; - if (!sk->reuse) - { - sti(); - return(-EADDRINUSE); - } - - if (sk2->num != snum) - continue; /* more than one */ - if (sk2->saddr != sk->saddr) - continue; /* socket per slot ! -FB */ - if (!sk2->reuse || sk2->state==TCP_LISTEN) - { - sti(); - return(-EADDRINUSE); - } - } - sti(); - - remove_sock(sk); - put_sock(snum, sk); - sk->dummy_th.source = ntohs(sk->num); - sk->daddr = 0; - sk->dummy_th.dest = 0; - } - return(0); -} - -/* - * Handle sk->err properly. The cli/sti matter. - */ - -static int inet_error(struct sock *sk) -{ - unsigned long flags; - int err; - save_flags(flags); - cli(); - err=sk->err; - sk->err=0; - restore_flags(flags); - return -err; -} - -/* - * Connect to a remote host. There is regrettably still a little - * TCP 'magic' in here. - */ - -static int inet_connect(struct socket *sock, struct sockaddr * uaddr, - int addr_len, int flags) -{ - struct sock *sk=(struct sock *)sock->data; - int err; - sock->conn = NULL; - - if (sock->state == SS_CONNECTING && tcp_connected(sk->state)) - { - sock->state = SS_CONNECTED; - /* Connection completing after a connect/EINPROGRESS/select/connect */ - return 0; /* Rock and roll */ - } - - if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK)) - return -EALREADY; /* Connecting is currently in progress */ - - if (sock->state != SS_CONNECTING) - { - /* We may need to bind the socket. */ - if(inet_autobind(sk)!=0) - return(-EAGAIN); - if (sk->prot->connect == NULL) - return(-EOPNOTSUPP); - err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len); - if (err < 0) - return(err); - sock->state = SS_CONNECTING; - } - - if (sk->state > TCP_FIN_WAIT2 && sock->state==SS_CONNECTING) - { - sock->state=SS_UNCONNECTED; - cli(); - err=sk->err; - sk->err=0; - sti(); - return -err; - } - - if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) - return(-EINPROGRESS); - - cli(); /* avoid the race condition */ - while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) - { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) - { - sti(); - return(-ERESTARTSYS); - } - /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with - icmp error packets wanting to close a tcp or udp socket. */ - if(sk->err && sk->protocol == IPPROTO_TCP) - { - sti(); - sock->state = SS_UNCONNECTED; - err = -sk->err; - sk->err=0; - return err; /* set by tcp_err() */ - } - } - sti(); - sock->state = SS_CONNECTED; - - if (sk->state != TCP_ESTABLISHED && sk->err) - { - sock->state = SS_UNCONNECTED; - err=sk->err; - sk->err=0; - return(-err); - } - return(0); -} - - -static int inet_socketpair(struct socket *sock1, struct socket *sock2) -{ - return(-EOPNOTSUPP); -} - - -/* - * Accept a pending connection. The TCP layer now gives BSD semantics. - */ - -static int inet_accept(struct socket *sock, struct socket *newsock, int flags) -{ - struct sock *sk1, *sk2; - int err; - - sk1 = (struct sock *) sock->data; - - /* - * We've been passed an extra socket. - * We need to free it up because the tcp module creates - * its own when it accepts one. - */ - if (newsock->data) - { - struct sock *sk=(struct sock *)newsock->data; - newsock->data=NULL; - sk->dead = 1; - destroy_sock(sk); - } - - if (sk1->prot->accept == NULL) - return(-EOPNOTSUPP); - - /* Restore the state if we have been interrupted, and then returned. */ - if (sk1->pair != NULL ) - { - sk2 = sk1->pair; - sk1->pair = NULL; - } - else - { - sk2 = sk1->prot->accept(sk1,flags); - if (sk2 == NULL) - { - if (sk1->err <= 0) - printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n"); - err=sk1->err; - sk1->err=0; - return(-err); - } - } - newsock->data = (void *)sk2; - sk2->sleep = newsock->wait; - sk2->socket = newsock; - newsock->conn = NULL; - if (flags & O_NONBLOCK) - return(0); - - cli(); /* avoid the race. */ - while(sk2->state == TCP_SYN_RECV) - { - interruptible_sleep_on(sk2->sleep); - if (current->signal & ~current->blocked) - { - sti(); - sk1->pair = sk2; - sk2->sleep = NULL; - sk2->socket=NULL; - newsock->data = NULL; - return(-ERESTARTSYS); - } - } - sti(); - - if (sk2->state != TCP_ESTABLISHED && sk2->err > 0) - { - err = -sk2->err; - sk2->err=0; - sk2->dead=1; /* ANK */ - destroy_sock(sk2); - newsock->data = NULL; - return(err); - } - newsock->state = SS_CONNECTED; - return(0); -} - - -/* - * This does both peername and sockname. - */ - -static int inet_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) -{ - struct sockaddr_in *sin=(struct sockaddr_in *)uaddr; - struct sock *sk; - - sin->sin_family = AF_INET; - sk = (struct sock *) sock->data; - if (peer) - { - if (!tcp_connected(sk->state)) - return(-ENOTCONN); - sin->sin_port = sk->dummy_th.dest; - sin->sin_addr.s_addr = sk->daddr; - } - else - { - sin->sin_port = sk->dummy_th.source; - if (sk->saddr == 0) - sin->sin_addr.s_addr = ip_my_addr(); - else - sin->sin_addr.s_addr = sk->saddr; - } - *uaddr_len = sizeof(*sin); - return(0); -} - - -/* - * The assorted BSD I/O operations - */ - -static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sin, int *addr_len ) -{ - struct sock *sk = (struct sock *) sock->data; - - if (sk->prot->recvfrom == NULL) - return(-EOPNOTSUPP); - if(sk->err) - return inet_error(sk); - /* We may need to bind the socket. */ - if(inet_autobind(sk)!=0) - return(-EAGAIN); - return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags, - (struct sockaddr_in*)sin, addr_len)); -} - - -static int inet_recv(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags) -{ - /* BSD explicitly states these are the same - so we do it this way to be sure */ - return inet_recvfrom(sock,ubuf,size,noblock,flags,NULL,NULL); -} - -static int inet_read(struct socket *sock, char *ubuf, int size, int noblock) -{ - struct sock *sk = (struct sock *) sock->data; - - if(sk->err) - return inet_error(sk); - /* We may need to bind the socket. */ - if(inet_autobind(sk)) - return(-EAGAIN); - return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, 0)); -} - -static int inet_send(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags) -{ - struct sock *sk = (struct sock *) sock->data; - if (sk->shutdown & SEND_SHUTDOWN) - { - send_sig(SIGPIPE, current, 1); - return(-EPIPE); - } - if(sk->err) - return inet_error(sk); - /* We may need to bind the socket. */ - if(inet_autobind(sk)!=0) - return(-EAGAIN); - return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags)); -} - -static int inet_write(struct socket *sock, char *ubuf, int size, int noblock) -{ - return inet_send(sock,ubuf,size,noblock,0); -} - -static int inet_sendto(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sin, int addr_len) -{ - struct sock *sk = (struct sock *) sock->data; - if (sk->shutdown & SEND_SHUTDOWN) - { - send_sig(SIGPIPE, current, 1); - return(-EPIPE); - } - if (sk->prot->sendto == NULL) - return(-EOPNOTSUPP); - if(sk->err) - return inet_error(sk); - /* We may need to bind the socket. */ - if(inet_autobind(sk)!=0) - return -EAGAIN; - return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags, - (struct sockaddr_in *)sin, addr_len)); -} - - -static int inet_shutdown(struct socket *sock, int how) -{ - struct sock *sk=(struct sock*)sock->data; - - /* - * This should really check to make sure - * the socket is a TCP socket. (WHY AC...) - */ - how++; /* maps 0->1 has the advantage of making bit 1 rcvs and - 1->2 bit 2 snds. - 2->3 */ - if ((how & ~SHUTDOWN_MASK) || how==0) /* MAXINT->0 */ - return(-EINVAL); - if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) - sock->state = SS_CONNECTED; - if (!tcp_connected(sk->state)) - return(-ENOTCONN); - sk->shutdown |= how; - if (sk->prot->shutdown) - sk->prot->shutdown(sk, how); - return(0); -} - - -static int inet_select(struct socket *sock, int sel_type, select_table *wait ) -{ - struct sock *sk=(struct sock *) sock->data; - if (sk->prot->select == NULL) - { - return(0); - } - return(sk->prot->select(sk, sel_type, wait)); -} - -#ifndef _HURD_ - -/* - * ioctl() calls you can issue on an INET socket. Most of these are - * device configuration and stuff and very rarely used. Some ioctls - * pass on to the socket itself. - * - * NOTE: I like the idea of a module for the config stuff. ie ifconfig - * loads the devconfigure module does its configuring and unloads it. - * There's a good 20K of config code hanging around the kernel. - */ - -static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk=(struct sock *)sock->data; - int err; - - switch(cmd) - { - case FIOSETOWN: - case SIOCSPGRP: - err=verify_area(VERIFY_READ,(int *)arg,sizeof(long)); - if(err) - return err; - sk->proc = get_fs_long((int *) arg); - return(0); - case FIOGETOWN: - case SIOCGPGRP: - err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long)); - if(err) - return err; - put_fs_long(sk->proc,(int *)arg); - return(0); - case SIOCGSTAMP: - if(sk->stamp.tv_sec==0) - return -ENOENT; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); - if(err) - return err; - memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval)); - return 0; - case SIOCADDRT: case SIOCADDRTOLD: - case SIOCDELRT: case SIOCDELRTOLD: - return(ip_rt_ioctl(cmd,(void *) arg)); - case SIOCDARP: - case SIOCGARP: - case SIOCSARP: - return(arp_ioctl(cmd,(void *) arg)); -#ifdef CONFIG_INET_RARP - case SIOCDRARP: - case SIOCGRARP: - case SIOCSRARP: - return(rarp_ioctl(cmd,(void *) arg)); -#endif - case SIOCGIFCONF: - case SIOCGIFFLAGS: - case SIOCSIFFLAGS: - case SIOCGIFADDR: - case SIOCSIFADDR: - -/* begin multicast support change */ - case SIOCADDMULTI: - case SIOCDELMULTI: -/* end multicast support change */ - - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - case SIOCGIFMEM: - case SIOCSIFMEM: - case SIOCGIFMTU: - case SIOCSIFMTU: - case SIOCSIFLINK: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case OLD_SIOCGIFHWADDR: - case SIOCSIFMAP: - case SIOCGIFMAP: - case SIOCSIFSLAVE: - case SIOCGIFSLAVE: - return(dev_ioctl(cmd,(void *) arg)); - - default: - if ((cmd >= SIOCDEVPRIVATE) && - (cmd <= (SIOCDEVPRIVATE + 15))) - return(dev_ioctl(cmd,(void *) arg)); - - if (sk->prot->ioctl==NULL) - return(-EINVAL); - return(sk->prot->ioctl(sk, cmd, arg)); - } - /*NOTREACHED*/ - return(0); - -} -#else /* _HURD_ */ -static int inet_ioctl (struct socket *sock, - unsigned int cm, - unsigned long arg) -{ - return EOPNOTSUPP; -} -#endif - - -/* - * This routine must find a socket given a TCP or UDP header. - * Everything is assumed to be in net order. - * - * We give priority to more closely bound ports: if some socket - * is bound to a particular foreign address, it will get the packet - * rather than somebody listening to any address.. - */ - -struct sock *get_sock(struct proto *prot, unsigned short num, - unsigned long raddr, - unsigned short rnum, unsigned long laddr) -{ - struct sock *s; - struct sock *result = NULL; - int badness = -1; - unsigned short hnum; - - hnum = ntohs(num); - - /* - * SOCK_ARRAY_SIZE must be a power of two. This will work better - * than a prime unless 3 or more sockets end up using the same - * array entry. This should not be a problem because most - * well known sockets don't overlap that much, and for - * the other ones, we can just be careful about picking our - * socket number when we choose an arbitrary one. - */ - - for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)]; - s != NULL; s = s->next) - { - int score = 0; - - if (s->num != hnum) - continue; - - if(s->dead && (s->state == TCP_CLOSE)) - continue; - /* local address matches? */ - if (s->saddr) { - if (s->saddr != laddr) - continue; - score++; - } - /* remote address matches? */ - if (s->daddr) { - if (s->daddr != raddr) - continue; - score++; - } - /* remote port matches? */ - if (s->dummy_th.dest) { - if (s->dummy_th.dest != rnum) - continue; - score++; - } - /* perfect match? */ - if (score == 3) - return s; - /* no, check if this is the best so far.. */ - if (score <= badness) - continue; - result = s; - badness = score; - } - return result; -} - -/* - * Deliver a datagram to raw sockets. - */ - -struct sock *get_sock_raw(struct sock *sk, - unsigned short num, - unsigned long raddr, - unsigned long laddr) -{ - struct sock *s; - - s=sk; - - for(; s != NULL; s = s->next) - { - if (s->num != num) - continue; - if(s->dead && (s->state == TCP_CLOSE)) - continue; - if(s->daddr && s->daddr!=raddr) - continue; - if(s->saddr && s->saddr!=laddr) - continue; - return(s); - } - return(NULL); -} - -#ifdef CONFIG_IP_MULTICAST -/* - * Deliver a datagram to broadcast/multicast sockets. - */ - -struct sock *get_sock_mcast(struct sock *sk, - unsigned short num, - unsigned long raddr, - unsigned short rnum, unsigned long laddr) -{ - struct sock *s; - unsigned short hnum; - - hnum = ntohs(num); - - /* - * SOCK_ARRAY_SIZE must be a power of two. This will work better - * than a prime unless 3 or more sockets end up using the same - * array entry. This should not be a problem because most - * well known sockets don't overlap that much, and for - * the other ones, we can just be careful about picking our - * socket number when we choose an arbitrary one. - */ - - s=sk; - - for(; s != NULL; s = s->next) - { - if (s->num != hnum) - continue; - if(s->dead && (s->state == TCP_CLOSE)) - continue; - if(s->daddr && s->daddr!=raddr) - continue; - if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) - continue; - if(s->saddr && s->saddr!=laddr) - continue; - return(s); - } - return(NULL); -} - -#endif - -static struct proto_ops inet_proto_ops = { - AF_INET, - - inet_create, - inet_dup, - inet_release, - inet_bind, - inet_connect, - inet_socketpair, - inet_accept, - inet_getname, - inet_read, - inet_write, - inet_select, - inet_ioctl, - inet_listen, - inet_send, - inet_recv, - inet_sendto, - inet_recvfrom, - inet_shutdown, - inet_setsockopt, - inet_getsockopt, - inet_fcntl, -}; - -extern unsigned long seq_offset; - -/* - * Called by socket.c on kernel startup. - */ - -void inet_proto_init(struct net_proto *pro) -{ - struct inet_protocol *p; - int i; - - - printk("Swansea University Computer Society TCP/IP for NET3.019\n"); - - /* - * Tell SOCKET that we are alive... - */ - - (void) sock_register(inet_proto_ops.family, &inet_proto_ops); - - seq_offset = CURRENT_TIME*250; - - /* - * Add all the protocols. - */ - - for(i = 0; i < SOCK_ARRAY_SIZE; i++) - { - tcp_prot.sock_array[i] = NULL; - udp_prot.sock_array[i] = NULL; - raw_prot.sock_array[i] = NULL; - } - tcp_prot.inuse = 0; - tcp_prot.highestinuse = 0; - udp_prot.inuse = 0; - udp_prot.highestinuse = 0; - raw_prot.inuse = 0; - raw_prot.highestinuse = 0; - - printk("IP Protocols: "); - for(p = inet_protocol_base; p != NULL;) - { - struct inet_protocol *tmp = (struct inet_protocol *) p->next; - inet_add_protocol(p); - printk("%s%s",p->name,tmp?", ":"\n"); - p = tmp; - } - /* - * Set the ARP module up - */ - arp_init(); - /* - * Set the IP module up - */ - ip_init(); -} - diff --git a/pfinet/linux-inet/arp.c b/pfinet/linux-inet/arp.c deleted file mode 100644 index 5e00caf7..00000000 --- a/pfinet/linux-inet/arp.c +++ /dev/null @@ -1,1295 +0,0 @@ -/* linux/net/inet/arp.c - * - * Copyright (C) 1994 by Florian La Roche - * - * This module implements the Address Resolution Protocol ARP (RFC 826), - * which is used to convert IP addresses (or in the future maybe other - * high-level addresses into a low-level hardware address (like an Ethernet - * address). - * - * FIXME: - * Experiment with better retransmit timers - * Clean up the timer deletions - * If you create a proxy entry set your interface address to the address - * and then delete it, proxies may get out of sync with reality - check this - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * Fixes: - * Alan Cox : Removed the ethernet assumptions in Florian's code - * Alan Cox : Fixed some small errors in the ARP logic - * Alan Cox : Allow >4K in /proc - * Alan Cox : Make ARP add its own protocol entry - * - * Ross Martin : Rewrote arp_rcv() and arp_get_info() - * Stephen Henson : Add AX25 support to arp_get_info() - * Alan Cox : Drop data when a device is downed. - * Alan Cox : Use init_timer(). - * Alan Cox : Double lock fixes. - * Martin Seine : Move the arphdr structure - * to if_arp.h for compatibility. - * with BSD based programs. - * Andrew Tridgell : Added ARP netmask code and - * re-arranged proxy handling. - * Alan Cox : Changed to use notifiers. - * Niibe Yutaka : Reply for this device or proxies only. - * Alan Cox : Don't proxy across hardware types! - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "route.h" -#include "protocol.h" -#include "tcp.h" -#include -#include "sock.h" -#include "arp.h" -#ifdef CONFIG_AX25 -#include "ax25.h" -#endif - - -/* - * This structure defines the ARP mapping cache. As long as we make changes - * in this structure, we keep interrupts of. But normally we can copy the - * hardware address and the device pointer in a local variable and then make - * any "long calls" to send a packet out. - */ - -struct arp_table -{ - struct arp_table *next; /* Linked entry list */ - unsigned long last_used; /* For expiry */ - unsigned int flags; /* Control status */ - unsigned long ip; /* ip address of entry */ - unsigned long mask; /* netmask - used for generalised proxy arps (tridge) */ - unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ - unsigned char hlen; /* Length of hardware address */ - unsigned short htype; /* Type of hardware in use */ - struct device *dev; /* Device the entry is tied to */ - - /* - * The following entries are only used for unresolved hw addresses. - */ - - struct timer_list timer; /* expire timer */ - int retries; /* remaining retries */ - struct sk_buff_head skb; /* list of queued packets */ -}; - - -/* - * Configurable Parameters (don't touch unless you know what you are doing - */ - -/* - * If an arp request is send, ARP_RES_TIME is the timeout value until the - * next request is send. - */ - -#define ARP_RES_TIME (250*(HZ/10)) - -/* - * The number of times an arp request is send, until the host is - * considered unreachable. - */ - -#define ARP_MAX_TRIES 3 - -/* - * After that time, an unused entry is deleted from the arp table. - */ - -#define ARP_TIMEOUT (600*HZ) - -/* - * How often is the function 'arp_check_retries' called. - * An entry is invalidated in the time between ARP_TIMEOUT and - * (ARP_TIMEOUT+ARP_CHECK_INTERVAL). - */ - -#define ARP_CHECK_INTERVAL (60 * HZ) - -enum proxy { - PROXY_EXACT=0, - PROXY_ANY, - PROXY_NONE, -}; - -/* Forward declarations. */ -static void arp_check_expire (unsigned long); -static struct arp_table *arp_lookup(unsigned long paddr, enum proxy proxy); - - -static struct timer_list arp_timer = - { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire }; - -/* - * The default arp netmask is just 255.255.255.255 which means it's - * a single machine entry. Only proxy entries can have other netmasks - * -*/ - -#define DEF_ARP_NETMASK (~0) - - -/* - * The size of the hash table. Must be a power of two. - * Maybe we should remove hashing in the future for arp and concentrate - * on Patrick Schaaf's Host-Cache-Lookup... - */ - - -#define ARP_TABLE_SIZE 16 - -/* The ugly +1 here is to cater for proxy entries. They are put in their - own list for efficiency of lookup. If you don't want to find a proxy - entry then don't look in the last entry, otherwise do -*/ - -#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1) - -struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] = -{ - NULL, -}; - - -/* - * The last bits in the IP address are used for the cache lookup. - * A special entry is used for proxy arp entries - */ - -#define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1)) -#define PROXY_HASH ARP_TABLE_SIZE - -/* - * Check if there are too old entries and remove them. If the ATF_PERM - * flag is set, they are always left in the arp cache (permanent entry). - * Note: Only fully resolved entries, which don't have any packets in - * the queue, can be deleted, since ARP_TIMEOUT is much greater than - * ARP_MAX_TRIES*ARP_RES_TIME. - */ - -static void arp_check_expire(unsigned long dummy) -{ - int i; - unsigned long now = jiffies; - unsigned long flags; - save_flags(flags); - cli(); - - for (i = 0; i < FULL_ARP_TABLE_SIZE; i++) - { - struct arp_table *entry; - struct arp_table **pentry = &arp_tables[i]; - - while ((entry = *pentry) != NULL) - { - if ((now - entry->last_used) > ARP_TIMEOUT - && !(entry->flags & ATF_PERM)) - { - *pentry = entry->next; /* remove from list */ - del_timer(&entry->timer); /* Paranoia */ - kfree_s(entry, sizeof(struct arp_table)); - } - else - pentry = &entry->next; /* go to next entry */ - } - } - restore_flags(flags); - - /* - * Set the timer again. - */ - - del_timer(&arp_timer); - arp_timer.expires = ARP_CHECK_INTERVAL; - add_timer(&arp_timer); -} - - -/* - * Release all linked skb's and the memory for this entry. - */ - -static void arp_release_entry(struct arp_table *entry) -{ - struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); - cli(); - /* Release the list of `skb' pointers. */ - while ((skb = skb_dequeue(&entry->skb)) != NULL) - { - skb_device_lock(skb); - restore_flags(flags); - dev_kfree_skb(skb, FREE_WRITE); - } - restore_flags(flags); - del_timer(&entry->timer); - kfree_s(entry, sizeof(struct arp_table)); - return; -} - -/* - * Purge a device from the ARP queue - */ - -int arp_device_event(unsigned long event, void *ptr) -{ - struct device *dev=ptr; - int i; - unsigned long flags; - - if(event!=NETDEV_DOWN) - return NOTIFY_DONE; - /* - * This is a bit OTT - maybe we need some arp semaphores instead. - */ - - save_flags(flags); - cli(); - for (i = 0; i < FULL_ARP_TABLE_SIZE; i++) - { - struct arp_table *entry; - struct arp_table **pentry = &arp_tables[i]; - - while ((entry = *pentry) != NULL) - { - if(entry->dev==dev) - { - *pentry = entry->next; /* remove from list */ - del_timer(&entry->timer); /* Paranoia */ - kfree_s(entry, sizeof(struct arp_table)); - } - else - pentry = &entry->next; /* go to next entry */ - } - } - restore_flags(flags); - return NOTIFY_DONE; -} - - -/* - * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast - * message. - */ - -void arp_send(int type, int ptype, unsigned long dest_ip, - struct device *dev, unsigned long src_ip, - unsigned char *dest_hw, unsigned char *src_hw) -{ - struct sk_buff *skb; - struct arphdr *arp; - unsigned char *arp_ptr; - - /* - * No arp on this interface. - */ - - if(dev->flags&IFF_NOARP) - return; - - /* - * Allocate a buffer - */ - - skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) - + dev->hard_header_len, GFP_ATOMIC); - if (skb == NULL) - { - printk("ARP: no memory to send an arp packet\n"); - return; - } - skb->len = sizeof(struct arphdr) + dev->hard_header_len + 2*(dev->addr_len+4); - skb->arp = 1; - skb->dev = dev; - skb->free = 1; - - /* - * Fill the device header for the ARP frame - */ - - dev->hard_header(skb->data,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len,skb); - - /* Fill out the arp protocol part. */ - arp = (struct arphdr *) (skb->data + dev->hard_header_len); - arp->ar_hrd = htons(dev->type); -#ifdef CONFIG_AX25 - arp->ar_pro = (dev->type != ARPHRD_AX25)? htons(ETH_P_IP) : htons(AX25_P_IP); -#else - arp->ar_pro = htons(ETH_P_IP); -#endif - arp->ar_hln = dev->addr_len; - arp->ar_pln = 4; - arp->ar_op = htons(type); - - arp_ptr=(unsigned char *)(arp+1); - - memcpy(arp_ptr, src_hw, dev->addr_len); - arp_ptr+=dev->addr_len; - memcpy(arp_ptr, &src_ip,4); - arp_ptr+=4; - if (dest_hw != NULL) - memcpy(arp_ptr, dest_hw, dev->addr_len); - else - memset(arp_ptr, 0, dev->addr_len); - arp_ptr+=dev->addr_len; - memcpy(arp_ptr, &dest_ip, 4); - - dev_queue_xmit(skb, dev, 0); -} - - -/* - * This function is called, if an entry is not resolved in ARP_RES_TIME. - * Either resend a request, or give it up and free the entry. - */ - -static void arp_expire_request (unsigned long arg) -{ - struct arp_table *entry = (struct arp_table *) arg; - struct arp_table **pentry; - unsigned long hash; - unsigned long flags; - - save_flags(flags); - cli(); - - /* - * Since all timeouts are handled with interrupts enabled, there is a - * small chance, that this entry has just been resolved by an incoming - * packet. This is the only race condition, but it is handled... - */ - - if (entry->flags & ATF_COM) - { - restore_flags(flags); - return; - } - - if (--entry->retries > 0) - { - unsigned long ip = entry->ip; - struct device *dev = entry->dev; - - /* Set new timer. */ - del_timer(&entry->timer); - entry->timer.expires = ARP_RES_TIME; - add_timer(&entry->timer); - restore_flags(flags); - arp_send(ARPOP_REQUEST, ETH_P_ARP, ip, dev, dev->pa_addr, - NULL, dev->dev_addr); - return; - } - - /* - * Arp request timed out. Delete entry and all waiting packets. - * If we give each entry a pointer to itself, we don't have to - * loop through everything again. Maybe hash is good enough, but - * I will look at it later. - */ - - hash = HASH(entry->ip); - - /* proxy entries shouldn't really time out so this is really - only here for completeness - */ - if (entry->flags & ATF_PUBL) - pentry = &arp_tables[PROXY_HASH]; - else - pentry = &arp_tables[hash]; - while (*pentry != NULL) - { - if (*pentry == entry) - { - *pentry = entry->next; /* delete from linked list */ - del_timer(&entry->timer); - restore_flags(flags); - arp_release_entry(entry); - return; - } - pentry = &(*pentry)->next; - } - restore_flags(flags); - printk("Possible ARP queue corruption.\n"); - /* - * We should never arrive here. - */ -} - - -/* - * This will try to retransmit everything on the queue. - */ - -static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest) -{ - struct sk_buff *skb; - - unsigned long flags; - - /* - * Empty the entire queue, building its data up ready to send - */ - - if(!(entry->flags&ATF_COM)) - { - printk("arp_send_q: incomplete entry for %s\n", - in_ntoa(entry->ip)); - return; - } - - save_flags(flags); - - cli(); - while((skb = skb_dequeue(&entry->skb)) != NULL) - { - IS_SKB(skb); - skb_device_lock(skb); - restore_flags(flags); - if(!skb->dev->rebuild_header(skb->data,skb->dev,skb->raddr,skb)) - { - skb->arp = 1; - if(skb->sk==NULL) - dev_queue_xmit(skb, skb->dev, 0); - else - dev_queue_xmit(skb,skb->dev,skb->sk->priority); - } - else - { - /* This routine is only ever called when 'entry' is - complete. Thus this can't fail. */ - printk("arp_send_q: The impossible occurred. Please notify Alan.\n"); - printk("arp_send_q: active entity %s\n",in_ntoa(entry->ip)); - printk("arp_send_q: failed to find %s\n",in_ntoa(skb->raddr)); - } - } - restore_flags(flags); -} - - -/* - * Delete an ARP mapping entry in the cache. - */ - -void arp_destroy(unsigned long ip_addr, int force) -{ - int checked_proxies = 0; - struct arp_table *entry; - struct arp_table **pentry; - unsigned long hash = HASH(ip_addr); - -ugly: - cli(); - pentry = &arp_tables[hash]; - if (! *pentry) /* also check proxy entries */ - pentry = &arp_tables[PROXY_HASH]; - - while ((entry = *pentry) != NULL) - { - if (entry->ip == ip_addr) - { - if ((entry->flags & ATF_PERM) && !force) - return; - *pentry = entry->next; - del_timer(&entry->timer); - sti(); - arp_release_entry(entry); - /* this would have to be cleaned up */ - goto ugly; - /* perhaps like this ? - cli(); - entry = *pentry; - */ - } - pentry = &entry->next; - if (!checked_proxies && ! *pentry) - { /* ugly. we have to make sure we check proxy - entries as well */ - checked_proxies = 1; - pentry = &arp_tables[PROXY_HASH]; - } - } - sti(); -} - - -/* - * Receive an arp request by the device layer. Maybe I rewrite it, to - * use the incoming packet for the reply. The time for the current - * "overhead" isn't that high... - */ - -int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ -/* - * We shouldn't use this type conversion. Check later. - */ - - struct arphdr *arp = (struct arphdr *)skb->h.raw; - unsigned char *arp_ptr= (unsigned char *)(arp+1); - struct arp_table *entry; - struct arp_table *proxy_entry; - int addr_hint,hlen,htype; - unsigned long hash; - unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */ - long sip,tip; - unsigned char *sha,*tha; - -/* - * The hardware length of the packet should match the hardware length - * of the device. Similarly, the hardware types should match. The - * device should be ARP-able. Also, if pln is not 4, then the lookup - * is not from an IP number. We can't currently handle this, so toss - * it. - */ - if (arp->ar_hln != dev->addr_len || - dev->type != ntohs(arp->ar_hrd) || - dev->flags & IFF_NOARP || - arp->ar_pln != 4) - { - kfree_skb(skb, FREE_READ); - return 0; - } - -/* - * Another test. - * The logic here is that the protocol being looked up by arp should - * match the protocol the device speaks. If it doesn't, there is a - * problem, so toss the packet. - */ - switch(dev->type) - { -#ifdef CONFIG_AX25 - case ARPHRD_AX25: - if(arp->ar_pro != htons(AX25_P_IP)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - break; -#endif - case ARPHRD_ETHER: - case ARPHRD_ARCNET: - if(arp->ar_pro != htons(ETH_P_IP)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - break; - - default: - printk("ARP: dev->type mangled!\n"); - kfree_skb(skb, FREE_READ); - return 0; - } - -/* - * Extract fields - */ - - hlen = dev->addr_len; - htype = dev->type; - - sha=arp_ptr; - arp_ptr+=hlen; - memcpy(&sip,arp_ptr,4); - arp_ptr+=4; - tha=arp_ptr; - arp_ptr+=hlen; - memcpy(&tip,arp_ptr,4); - -/* - * Check for bad requests for 127.0.0.1. If this is one such, delete it. - */ - if(tip == INADDR_LOOPBACK) - { - kfree_skb(skb, FREE_READ); - return 0; - } - -/* - * Process entry. The idea here is we want to send a reply if it is a - * request for us or if it is a request for someone else that we hold - * a proxy for. We want to add an entry to our cache if it is a reply - * to us or if it is a request for our address. - * (The assumption for this last is that if someone is requesting our - * address, they are probably intending to talk to us, so it saves time - * if we cache their address. Their address is also probably not in - * our cache, since ours is not in their cache.) - * - * Putting this another way, we only care about replies if they are to - * us, in which case we add them to the cache. For requests, we care - * about those for us and those for our proxies. We reply to both, - * and in the case of requests for us we add the requester to the arp - * cache. - */ - - addr_hint = ip_chk_addr(tip); - - if(arp->ar_op == htons(ARPOP_REPLY)) - { - if(addr_hint!=IS_MYADDR) - { -/* - * Replies to other machines get tossed. - */ - kfree_skb(skb, FREE_READ); - return 0; - } -/* - * Fall through to code below that adds sender to cache. - */ - } - else - { -/* - * It is now an arp request - */ -/* - * Only reply for the real device address or when it's in our proxy tables - */ - if(tip!=dev->pa_addr) - { -/* - * To get in here, it is a request for someone else. We need to - * check if that someone else is one of our proxies. If it isn't, - * we can toss it. - */ - cli(); - for(proxy_entry=arp_tables[PROXY_HASH]; - proxy_entry; - proxy_entry = proxy_entry->next) - { - /* we will respond to a proxy arp request - if the masked arp table ip matches the masked - tip. This allows a single proxy arp table - entry to be used on a gateway machine to handle - all requests for a whole network, rather than - having to use a huge number of proxy arp entries - and having to keep them uptodate. - */ - if (proxy_entry->dev != dev && proxy_entry->htype == htype && - !((proxy_entry->ip^tip)&proxy_entry->mask)) - break; - - } - if (proxy_entry) - { - memcpy(ha, proxy_entry->ha, hlen); - sti(); - arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha); - kfree_skb(skb, FREE_READ); - return 0; - } - else - { - sti(); - kfree_skb(skb, FREE_READ); - return 0; - } - } - else - { -/* - * To get here, it must be an arp request for us. We need to reply. - */ - arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr); - } - } - - -/* - * Now all replies are handled. Next, anything that falls through to here - * needs to be added to the arp cache, or have its entry updated if it is - * there. - */ - - hash = HASH(sip); - cli(); - for(entry=arp_tables[hash];entry;entry=entry->next) - if(entry->ip==sip && entry->htype==htype) - break; - - if(entry) - { -/* - * Entry found; update it. - */ - memcpy(entry->ha, sha, hlen); - entry->hlen = hlen; - entry->last_used = jiffies; - if (!(entry->flags & ATF_COM)) - { -/* - * This entry was incomplete. Delete the retransmit timer - * and switch to complete status. - */ - del_timer(&entry->timer); - entry->flags |= ATF_COM; - sti(); -/* - * Send out waiting packets. We might have problems, if someone is - * manually removing entries right now -- entry might become invalid - * underneath us. - */ - arp_send_q(entry, sha); - } - else - { - sti(); - } - } - else - { -/* - * No entry found. Need to add a new entry to the arp table. - */ - entry = (struct arp_table *)kmalloc(sizeof(struct arp_table),GFP_ATOMIC); - if(entry == NULL) - { - sti(); - printk("ARP: no memory for new arp entry\n"); - - kfree_skb(skb, FREE_READ); - return 0; - } - - entry->mask = DEF_ARP_NETMASK; - entry->ip = sip; - entry->hlen = hlen; - entry->htype = htype; - entry->flags = ATF_COM; - init_timer(&entry->timer); - memcpy(entry->ha, sha, hlen); - entry->last_used = jiffies; - entry->dev = skb->dev; - skb_queue_head_init(&entry->skb); - entry->next = arp_tables[hash]; - arp_tables[hash] = entry; - sti(); - } - -/* - * Replies have been sent, and entries have been added. All done. - */ - kfree_skb(skb, FREE_READ); - return 0; -} - - -/* - * Find an arp mapping in the cache. If not found, post a request. - */ - -int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, - unsigned long saddr, struct sk_buff *skb) -{ - struct arp_table *entry; - unsigned long hash; -#ifdef CONFIG_IP_MULTICAST - unsigned long taddr; -#endif - - switch (ip_chk_addr(paddr)) - { - case IS_MYADDR: - printk("ARP: arp called for own IP address\n"); - memcpy(haddr, dev->dev_addr, dev->addr_len); - skb->arp = 1; - return 0; -#ifdef CONFIG_IP_MULTICAST - case IS_MULTICAST: - if(dev->type==ARPHRD_ETHER || dev->type==ARPHRD_IEEE802) - { - haddr[0]=0x01; - haddr[1]=0x00; - haddr[2]=0x5e; - taddr=ntohl(paddr); - haddr[5]=taddr&0xff; - taddr=taddr>>8; - haddr[4]=taddr&0xff; - taddr=taddr>>8; - haddr[3]=taddr&0x7f; - return 0; - } - /* - * If a device does not support multicast broadcast the stuff (eg AX.25 for now) - */ -#endif - - case IS_BROADCAST: - memcpy(haddr, dev->broadcast, dev->addr_len); - skb->arp = 1; - return 0; - } - - hash = HASH(paddr); - cli(); - - /* - * Find an entry - */ - entry = arp_lookup(paddr, PROXY_NONE); - - if (entry != NULL) /* It exists */ - { - if (!(entry->flags & ATF_COM)) - { - /* - * A request was already send, but no reply yet. Thus - * queue the packet with the previous attempt - */ - - if (skb != NULL) - { - skb_queue_tail(&entry->skb, skb); - skb_device_unlock(skb); - } - sti(); - return 1; - } - - /* - * Update the record - */ - - entry->last_used = jiffies; - memcpy(haddr, entry->ha, dev->addr_len); - if (skb) - skb->arp = 1; - sti(); - return 0; - } - - /* - * Create a new unresolved entry. - */ - - entry = (struct arp_table *) kmalloc(sizeof(struct arp_table), - GFP_ATOMIC); - if (entry != NULL) - { - entry->mask = DEF_ARP_NETMASK; - entry->ip = paddr; - entry->hlen = dev->addr_len; - entry->htype = dev->type; - entry->flags = 0; - memset(entry->ha, 0, dev->addr_len); - entry->dev = dev; - entry->last_used = jiffies; - init_timer(&entry->timer); - entry->timer.function = arp_expire_request; - entry->timer.data = (unsigned long)entry; - entry->timer.expires = ARP_RES_TIME; - entry->next = arp_tables[hash]; - arp_tables[hash] = entry; - add_timer(&entry->timer); - entry->retries = ARP_MAX_TRIES; - skb_queue_head_init(&entry->skb); - if (skb != NULL) - { - skb_queue_tail(&entry->skb, skb); - skb_device_unlock(skb); - } - } - else - { - if (skb != NULL && skb->free) - kfree_skb(skb, FREE_WRITE); - } - sti(); - - /* - * If we didn't find an entry, we will try to send an ARP packet. - */ - - arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, saddr, NULL, - dev->dev_addr); - - return 1; -} - - -/* - * Write the contents of the ARP cache to a PROCfs file. - */ - -#define HBUFFERLEN 30 - -int arp_get_info(char *buffer, char **start, off_t offset, int length) -{ - int len=0; - off_t begin=0; - off_t pos=0; - int size; - struct arp_table *entry; - char hbuffer[HBUFFERLEN]; - int i,j,k; - const char hexbuf[] = "0123456789ABCDEF"; - - size = sprintf(buffer,"IP address HW type Flags HW address Mask\n"); - - pos+=size; - len+=size; - - cli(); - for(i=0; inext) - { -/* - * Convert hardware address to XX:XX:XX:XX ... form. - */ -#ifdef CONFIG_AX25 - - if(entry->htype==ARPHRD_AX25) - strcpy(hbuffer,ax2asc((ax25_address *)entry->ha)); - else { -#endif - - for(k=0,j=0;khlen;j++) - { - hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ]; - hbuffer[k++]=hexbuf[ entry->ha[j]&15 ]; - hbuffer[k++]=':'; - } - hbuffer[--k]=0; - -#ifdef CONFIG_AX25 - } -#endif - size = sprintf(buffer+len, - "%-17s0x%-10x0x%-10x%s", - in_ntoa(entry->ip), - (unsigned int)entry->htype, - entry->flags, - hbuffer); - size += sprintf(buffer+len+size, - " %-17s\n", - entry->mask==DEF_ARP_NETMASK? - "*":in_ntoa(entry->mask)); - - len+=size; - pos=begin+len; - - if(posoffset+length) - break; - } - } - sti(); - - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len=length; /* Ending slop */ - return len; -} - - -/* - * This will find an entry in the ARP table by looking at the IP address. - * If proxy is PROXY_EXACT then only exact IP matches will be allowed - * for proxy entries, otherwise the netmask will be used - */ - -static struct arp_table *arp_lookup(unsigned long paddr, enum proxy proxy) -{ - struct arp_table *entry; - unsigned long hash = HASH(paddr); - - for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) - if (entry->ip == paddr) break; - - /* it's possibly a proxy entry (with a netmask) */ - if (!entry && proxy != PROXY_NONE) - for (entry=arp_tables[PROXY_HASH]; entry != NULL; entry = entry->next) - if ((proxy==PROXY_EXACT) ? (entry->ip==paddr) - : !((entry->ip^paddr)&entry->mask)) - break; - - return entry; -} - - -/* - * Set (create) an ARP cache entry. - */ - -static int arp_req_set(struct arpreq *req) -{ - struct arpreq r; - struct arp_table *entry; - struct sockaddr_in *si; - int htype, hlen; - unsigned long ip; - struct rtable *rt; - - memcpy_fromfs(&r, req, sizeof(r)); - - /* We only understand about IP addresses... */ - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - - /* - * Find out about the hardware type. - * We have to be compatible with BSD UNIX, so we have to - * assume that a "not set" value (i.e. 0) means Ethernet. - */ - - switch (r.arp_ha.sa_family) { - case ARPHRD_ETHER: - htype = ARPHRD_ETHER; - hlen = ETH_ALEN; - break; - - case ARPHRD_ARCNET: - htype = ARPHRD_ARCNET; - hlen = 1; /* length of arcnet addresses */ - break; - -#ifdef CONFIG_AX25 - case ARPHRD_AX25: - htype = ARPHRD_AX25; - hlen = 7; - break; -#endif - default: - return -EPFNOSUPPORT; - } - - si = (struct sockaddr_in *) &r.arp_pa; - ip = si->sin_addr.s_addr; - if (ip == 0) - { - printk("ARP: SETARP: requested PA is 0.0.0.0 !\n"); - return -EINVAL; - } - - /* - * Is it reachable directly ? - */ - - rt = ip_rt_route(ip, NULL, NULL); - if (rt == NULL) - return -ENETUNREACH; - - /* - * Is there an existing entry for this address? - */ - - cli(); - - /* - * Find the entry - */ - entry = arp_lookup(ip, PROXY_EXACT); - if (entry && (entry->flags & ATF_PUBL) != (r.arp_flags & ATF_PUBL)) - { - sti(); - arp_destroy(ip,1); - cli(); - entry = NULL; - } - - /* - * Do we need to create a new entry - */ - - if (entry == NULL) - { - unsigned long hash = HASH(ip); - if (r.arp_flags & ATF_PUBL) - hash = PROXY_HASH; - - entry = (struct arp_table *) kmalloc(sizeof(struct arp_table), - GFP_ATOMIC); - if (entry == NULL) - { - sti(); - return -ENOMEM; - } - entry->ip = ip; - entry->hlen = hlen; - entry->htype = htype; - init_timer(&entry->timer); - entry->next = arp_tables[hash]; - arp_tables[hash] = entry; - skb_queue_head_init(&entry->skb); - } - /* - * We now have a pointer to an ARP entry. Update it! - */ - - memcpy(&entry->ha, &r.arp_ha.sa_data, hlen); - entry->last_used = jiffies; - entry->flags = r.arp_flags | ATF_COM; - if ((entry->flags & ATF_PUBL) && (entry->flags & ATF_NETMASK)) - { - si = (struct sockaddr_in *) &r.arp_netmask; - entry->mask = si->sin_addr.s_addr; - } - else - entry->mask = DEF_ARP_NETMASK; - entry->dev = rt->rt_dev; - sti(); - - return 0; -} - - -/* - * Get an ARP cache entry. - */ - -static int arp_req_get(struct arpreq *req) -{ - struct arpreq r; - struct arp_table *entry; - struct sockaddr_in *si; - - /* - * We only understand about IP addresses... - */ - - memcpy_fromfs(&r, req, sizeof(r)); - - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - - /* - * Is there an existing entry for this address? - */ - - si = (struct sockaddr_in *) &r.arp_pa; - cli(); - entry = arp_lookup(si->sin_addr.s_addr,PROXY_ANY); - - if (entry == NULL) - { - sti(); - return -ENXIO; - } - - /* - * We found it; copy into structure. - */ - - memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen); - r.arp_ha.sa_family = entry->htype; - r.arp_flags = entry->flags; - sti(); - - /* - * Copy the information back - */ - - memcpy_tofs(req, &r, sizeof(r)); - return 0; -} - - -#ifndef _HURD_ -/* - * Handle an ARP layer I/O control request. - */ - -int arp_ioctl(unsigned int cmd, void *arg) -{ - struct arpreq r; - struct sockaddr_in *si; - int err; - - switch(cmd) - { - case SIOCDARP: - if (!suser()) - return -EPERM; - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); - if(err) - return err; - memcpy_fromfs(&r, arg, sizeof(r)); - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - si = (struct sockaddr_in *) &r.arp_pa; - arp_destroy(si->sin_addr.s_addr, 1); - return 0; - case SIOCGARP: - err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq)); - if(err) - return err; - return arp_req_get((struct arpreq *)arg); - case SIOCSARP: - if (!suser()) - return -EPERM; - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); - if(err) - return err; - return arp_req_set((struct arpreq *)arg); - default: - return -EINVAL; - } - /*NOTREACHED*/ - return 0; -} -#endif - -/* - * Called once on startup. - */ - -static struct packet_type arp_packet_type = -{ - 0, /* Should be: __constant_htons(ETH_P_ARP) - but this _doesn't_ come out constant! */ - NULL, /* All devices */ - arp_rcv, - NULL, - NULL -}; - -static struct notifier_block arp_dev_notifier={ - arp_device_event, - NULL, - 0 -}; - -void arp_init (void) -{ - /* Register the packet type */ - arp_packet_type.type=htons(ETH_P_ARP); - dev_add_pack(&arp_packet_type); - /* Start with the regular checks for expired arp entries. */ - add_timer(&arp_timer); - /* Register for device down reports */ - register_netdevice_notifier(&arp_dev_notifier); -} - diff --git a/pfinet/linux-inet/arp.h b/pfinet/linux-inet/arp.h deleted file mode 100644 index a68adc30..00000000 --- a/pfinet/linux-inet/arp.h +++ /dev/null @@ -1,18 +0,0 @@ -/* linux/net/inet/arp.h */ -#ifndef _ARP_H -#define _ARP_H - -extern void arp_init(void); -extern void arp_destroy(unsigned long paddr, int force); -extern void arp_device_down(struct device *dev); -extern int arp_rcv(struct sk_buff *skb, struct device *dev, - struct packet_type *pt); -extern int arp_find(unsigned char *haddr, unsigned long paddr, - struct device *dev, unsigned long saddr, struct sk_buff *skb); -extern int arp_get_info(char *buffer, char **start, off_t origin, int length); -extern int arp_ioctl(unsigned int cmd, void *arg); -extern void arp_send(int type, int ptype, unsigned long dest_ip, - struct device *dev, unsigned long src_ip, - unsigned char *dest_hw, unsigned char *src_hw); - -#endif /* _ARP_H */ diff --git a/pfinet/linux-inet/datagram.c b/pfinet/linux-inet/datagram.c deleted file mode 100644 index cd248cfb..00000000 --- a/pfinet/linux-inet/datagram.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * SUCS NET3: - * - * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top - * of these would make sense. Not tonight however 8-). - * This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly - * identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it. - * - * Authors: Alan Cox . (datagram_select() from old udp.c code) - * - * Fixes: - * Alan Cox : NULL return from skb_peek_copy() understood - * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff. - * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but - * AX.25 now works right, and SPX is feasible. - * Alan Cox : Fixed write select of non IP protocol crash. - * Florian La Roche: Changed for my new skbuff handling. - * - * Note: - * A lot of this will change when the protocol/socket separation - * occurs. Using this will make things reasonably clean. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include "route.h" -#include "tcp.h" -#include "udp.h" -#include -#include "sock.h" - - -/* - * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible - * races. This replaces identical code in packet,raw and udp, as well as the yet to - * be released IPX support. It also finally fixes the long standing peek and read - * race for datagram sockets. If you alter this routine remember it must be - * re-entrant. - */ - -struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err) -{ - struct sk_buff *skb; - unsigned long intflags; - - /* Socket is inuse - so the timer doesn't attack it */ - save_flags(intflags); -restart: - sk->inuse = 1; - while(skb_peek(&sk->receive_queue) == NULL) /* No data */ - { - /* If we are shutdown then no more data is going to appear. We are done */ - if (sk->shutdown & RCV_SHUTDOWN) - { - release_sock(sk); - *err=0; - return NULL; - } - - if(sk->err) - { - release_sock(sk); - *err=-sk->err; - sk->err=0; - return NULL; - } - - /* Sequenced packets can come disconnected. If so we report the problem */ - if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED) - { - release_sock(sk); - *err=-ENOTCONN; - return NULL; - } - - /* User doesn't want to wait */ - if (noblock) - { - release_sock(sk); - *err=-EAGAIN; - return NULL; - } - release_sock(sk); - - /* Interrupts off so that no packet arrives before we begin sleeping. - Otherwise we might miss our wake up */ - cli(); - if (skb_peek(&sk->receive_queue) == NULL) - { - interruptible_sleep_on(sk->sleep); - /* Signals may need a restart of the syscall */ - if (current->signal & ~current->blocked) - { - restore_flags(intflags);; - *err=-ERESTARTSYS; - return(NULL); - } - if(sk->err != 0) /* Error while waiting for packet - eg an icmp sent earlier by the - peer has finally turned up now */ - { - *err = -sk->err; - sk->err=0; - restore_flags(intflags); - return NULL; - } - } - sk->inuse = 1; - restore_flags(intflags); - } - /* Again only user level code calls this function, so nothing interrupt level - will suddenly eat the receive_queue */ - if (!(flags & MSG_PEEK)) - { - skb=skb_dequeue(&sk->receive_queue); - if(skb!=NULL) - skb->users++; - else - goto restart; /* Avoid race if someone beats us to the data */ - } - else - { - cli(); - skb=skb_peek(&sk->receive_queue); - if(skb!=NULL) - skb->users++; - restore_flags(intflags); - if(skb==NULL) /* shouldn't happen but .. */ - *err=-EAGAIN; - } - return skb; -} - -void skb_free_datagram(struct sk_buff *skb) -{ - unsigned long flags; - - save_flags(flags); - cli(); - skb->users--; - if(skb->users>0) - { - restore_flags(flags); - return; - } - /* See if it needs destroying */ - if(!skb->next && !skb->prev) /* Been dequeued by someone - ie it's read */ - kfree_skb(skb,FREE_READ); - restore_flags(flags); -} - -void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) -{ - /* We will know all about the fraglist options to allow >4K receives - but not this release */ - memcpy_tofs(to,skb->h.raw+offset,size); -} - -/* - * Datagram select: Again totally generic. Moved from udp.c - * Now does seqpacket. - */ - -int datagram_select(struct sock *sk, int sel_type, select_table *wait) -{ - select_wait(sk->sleep, wait); - switch(sel_type) - { - case SEL_IN: - if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE) - { - /* Connection closed: Wake up */ - return(1); - } - if (skb_peek(&sk->receive_queue) != NULL || sk->err != 0) - { /* This appears to be consistent - with other stacks */ - return(1); - } - return(0); - - case SEL_OUT: - if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE) - { - return(1); - } - if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE) - { - return(1); - } - return(0); - - case SEL_EX: - if (sk->err) - return(1); /* Socket has gone into error state (eg icmp error) */ - return(0); - } - return(0); -} diff --git a/pfinet/linux-inet/datalink.h b/pfinet/linux-inet/datalink.h deleted file mode 100644 index 34ae08da..00000000 --- a/pfinet/linux-inet/datalink.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _NET_INET_DATALINK_H_ -#define _NET_INET_DATALINK_H_ - -struct datalink_proto { - unsigned short type_len; - unsigned char type[8]; - char *string_name; - unsigned short header_length; - int (*rcvfunc)(struct sk_buff *, struct device *, - struct packet_type *); - void (*datalink_header)(struct datalink_proto *, struct sk_buff *, - unsigned char *); - struct datalink_proto *next; -}; - -#endif - diff --git a/pfinet/linux-inet/dev.c b/pfinet/linux-inet/dev.c deleted file mode 100644 index d393af11..00000000 --- a/pfinet/linux-inet/dev.c +++ /dev/null @@ -1,1449 +0,0 @@ -/* - * NET3 Protocol independent device support routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Derived from the non IP parts of dev.c 1.0.19 - * Authors: Ross Biro, - * Fred N. van Kempen, - * Mark Evans, - * - * Additional Authors: - * Florian la Roche - * Alan Cox - * David Hinds - * - * Changes: - * Alan Cox : device private ioctl copies fields back. - * Alan Cox : Transmit queue code does relevant stunts to - * keep the queue safe. - * Alan Cox : Fixed double lock. - * Alan Cox : Fixed promisc NULL pointer trap - * ???????? : Support the full private ioctl range - * Alan Cox : Moved ioctl permission check into drivers - * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI - * Alan Cox : 100 backlog just doesn't cut it when - * you start doing multicast video 8) - * Alan Cox : Rewrote net_bh and list manager. - * Alan Cox : Fix ETH_P_ALL echoback lengths. - * - * Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have - * the rest as well commented in the end. - */ - -/* - * A lot of these includes will be going walkies very soon - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "route.h" -#include -#include "sock.h" -#include "arp.h" - - -/* - * The list of packet types we will receive (as opposed to discard) - * and the routines to invoke. - */ - -struct packet_type *ptype_base = NULL; - -/* - * Our notifier list - */ - -struct notifier_block *netdev_chain=NULL; - -/* - * Device drivers call our routines to queue packets here. We empty the - * queue in the bottom half handler. - */ - -static struct sk_buff_head backlog = -{ - (struct sk_buff *)&backlog, (struct sk_buff *)&backlog -#ifdef CONFIG_SKB_CHECK - ,SK_HEAD_SKB -#endif -}; - -/* - * We don't overdo the queue or we will thrash memory badly. - */ - -static int backlog_size = 0; - -/* - * Return the lesser of the two values. - */ - -static __inline__ unsigned long min(unsigned long a, unsigned long b) -{ - return (a < b)? a : b; -} - - -/****************************************************************************************** - - Protocol management and registration routines - -*******************************************************************************************/ - -/* - * For efficiency - */ - -static int dev_nit=0; - -/* - * Add a protocol ID to the list. Now that the input handler is - * smarter we can dispense with all the messy stuff that used to be - * here. - */ - -void dev_add_pack(struct packet_type *pt) -{ - if(pt->type==htons(ETH_P_ALL)) - dev_nit++; - pt->next = ptype_base; - ptype_base = pt; -} - - -/* - * Remove a protocol ID from the list. - */ - -void dev_remove_pack(struct packet_type *pt) -{ - struct packet_type **pt1; - if(pt->type==htons(ETH_P_ALL)) - dev_nit--; - for(pt1=&ptype_base; (*pt1)!=NULL; pt1=&((*pt1)->next)) - { - if(pt==(*pt1)) - { - *pt1=pt->next; - return; - } - } -} - -/***************************************************************************************** - - Device Interface Subroutines - -******************************************************************************************/ - -/* - * Find an interface by name. - */ - -struct device *dev_get(char *name) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (strcmp(dev->name, name) == 0) - return(dev); - } - return(NULL); -} - - -/* - * Prepare an interface for use. - */ - -int dev_open(struct device *dev) -{ - int ret = 0; - - /* - * Call device private open method - */ - if (dev->open) - ret = dev->open(dev); - - /* - * If it went open OK then set the flags - */ - - if (ret == 0) - { - dev->flags |= (IFF_UP | IFF_RUNNING); - /* - * Initialise multicasting status - */ -#ifdef CONFIG_IP_MULTICAST - /* - * Join the all host group - */ - ip_mc_allhost(dev); -#endif - dev_mc_upload(dev); - notifier_call_chain(&netdev_chain, NETDEV_UP, dev); - } - return(ret); -} - - -/* - * Completely shutdown an interface. - */ - -int dev_close(struct device *dev) -{ - /* - * Only close a device if it is up. - */ - - if (dev->flags != 0) - { - int ct=0; - dev->flags = 0; - /* - * Call the device specific close. This cannot fail. - */ - if (dev->stop) - dev->stop(dev); - - notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); -#if 0 - /* - * Delete the route to the device. - */ -#ifdef CONFIG_INET - ip_rt_flush(dev); - arp_device_down(dev); -#endif -#ifdef CONFIG_IPX - ipxrtr_device_down(dev); -#endif -#endif - /* - * Flush the multicast chain - */ - dev_mc_discard(dev); - /* - * Blank the IP addresses - */ - dev->pa_addr = 0; - dev->pa_dstaddr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - /* - * Purge any queued packets when we down the link - */ - while(ctbuffs[ct]))!=NULL) - if(skb->free) - kfree_skb(skb,FREE_WRITE); - ct++; - } - } - return(0); -} - - -/* - * Device change register/unregister. These are not inline or static - * as we export them to the world. - */ - -int register_netdevice_notifier(struct notifier_block *nb) -{ - return notifier_chain_register(&netdev_chain, nb); -} - -int unregister_netdevice_notifier(struct notifier_block *nb) -{ - return notifier_chain_unregister(&netdev_chain,nb); -} - - - -/* - * Send (or queue for sending) a packet. - * - * IMPORTANT: When this is called to resend frames. The caller MUST - * already have locked the sk_buff. Apart from that we do the - * rest of the magic. - */ - -void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) -{ - unsigned long flags; - int nitcount; - struct packet_type *ptype; - int where = 0; /* used to say if the packet should go */ - /* at the front or the back of the */ - /* queue - front is a retransmit try */ - - if (dev == NULL) - { - printk("dev.c: dev_queue_xmit: dev = NULL\n"); - return; - } - - if(pri>=0 && !skb_device_locked(skb)) - skb_device_lock(skb); /* Shove a lock on the frame */ -#ifdef CONFIG_SLAVE_BALANCING - save_flags(flags); - cli(); - if(dev->slave!=NULL && dev->slave->pkt_queue < dev->pkt_queue && - (dev->slave->flags & IFF_UP)) - dev=dev->slave; - restore_flags(flags); -#endif -#ifdef CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - skb->dev = dev; - - /* - * This just eliminates some race conditions, but not all... - */ - - if (skb->next != NULL) - { - /* - * Make sure we haven't missed an interrupt. - */ - printk("dev_queue_xmit: worked around a missed interrupt\n"); - dev->hard_start_xmit(NULL, dev); - return; - } - - /* - * Negative priority is used to flag a frame that is being pulled from the - * queue front as a retransmit attempt. It therefore goes back on the queue - * start on a failure. - */ - - if (pri < 0) - { - pri = -pri-1; - where = 1; - } - - if (pri >= DEV_NUMBUFFS) - { - printk("bad priority in dev_queue_xmit.\n"); - pri = 1; - } - - /* - * If the address has not been resolved. Call the device header rebuilder. - * This can cover all protocols and technically not just ARP either. - */ - - if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) { - return; - } - - save_flags(flags); - cli(); - if (!where) { -#ifdef CONFIG_SLAVE_BALANCING - skb->in_dev_queue=1; -#endif - skb_queue_tail(dev->buffs + pri,skb); - skb_device_unlock(skb); /* Buffer is on the device queue and can be freed safely */ - skb = skb_dequeue(dev->buffs + pri); - skb_device_lock(skb); /* New buffer needs locking down */ -#ifdef CONFIG_SLAVE_BALANCING - skb->in_dev_queue=0; -#endif - } - restore_flags(flags); - - /* copy outgoing packets to any sniffer packet handlers */ - if(!where) - { - for (nitcount= dev_nit, ptype = ptype_base; nitcount > 0 && ptype != NULL; ptype = ptype->next) - { - /* Never send packets back to the socket - * they originated from - MvS (miquels@drinkel.ow.org) - */ - if (ptype->type == htons(ETH_P_ALL) && - (ptype->dev == dev || !ptype->dev) && - ((struct sock *)ptype->data != skb->sk)) - { - struct sk_buff *skb2; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) - break; - /* - * The protocol knows this has (for other paths) been taken off - * and adds it back. - */ - skb2->len-=skb->dev->hard_header_len; - ptype->func(skb2, skb->dev, ptype); - nitcount--; - } - } - } - if (dev->hard_start_xmit(skb, dev) == 0) { - /* - * Packet is now solely the responsibility of the driver - */ - return; - } - - /* - * Transmission failed, put skb back into a list. Once on the list it's safe and - * no longer device locked (it can be freed safely from the device queue) - */ - cli(); -#ifdef CONFIG_SLAVE_BALANCING - skb->in_dev_queue=1; - dev->pkt_queue++; -#endif - skb_device_unlock(skb); - skb_queue_head(dev->buffs + pri,skb); - restore_flags(flags); -} - -/* - * Receive a packet from a device driver and queue it for the upper - * (protocol) levels. It always succeeds. This is the recommended - * interface to use. - */ - -void netif_rx(struct sk_buff *skb) -{ - static int dropping = 0; - - /* - * Any received buffers are un-owned and should be discarded - * when freed. These will be updated later as the frames get - * owners. - */ - skb->sk = NULL; - skb->free = 1; - if(skb->stamp.tv_sec==0) - skb->stamp = xtime; - - /* - * Check that we aren't overdoing things. - */ - - if (!backlog_size) - dropping = 0; - else if (backlog_size > 300) - dropping = 1; - - if (dropping) - { - kfree_skb(skb, FREE_READ); - return; - } - - /* - * Add it to the "backlog" queue. - */ -#ifdef CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - skb_queue_tail(&backlog,skb); - backlog_size++; - - /* - * If any packet arrived, mark it for processing after the - * hardware interrupt returns. - */ - - mark_bh(NET_BH); - return; -} - - -/* - * The old interface to fetch a packet from a device driver. - * This function is the base level entry point for all drivers that - * want to send a packet to the upper (protocol) levels. It takes - * care of de-multiplexing the packet to the various modules based - * on their protocol ID. - * - * Return values: 1 <- exit I can't do any more - * 0 <- feed me more (i.e. "done", "OK"). - * - * This function is OBSOLETE and should not be used by any new - * device. - */ - -int dev_rint(unsigned char *buff, long len, int flags, struct device *dev) -{ - static int dropping = 0; - struct sk_buff *skb = NULL; - unsigned char *to; - int amount, left; - int len2; - - if (dev == NULL || buff == NULL || len <= 0) - return(1); - - if (flags & IN_SKBUFF) - { - skb = (struct sk_buff *) buff; - } - else - { - if (dropping) - { - if (skb_peek(&backlog) != NULL) - return(1); - printk("INET: dev_rint: no longer dropping packets.\n"); - dropping = 0; - } - - skb = alloc_skb(len, GFP_ATOMIC); - if (skb == NULL) - { - printk("dev_rint: packet dropped on %s (no memory) !\n", - dev->name); - dropping = 1; - return(1); - } - - /* - * First we copy the packet into a buffer, and save it for later. We - * in effect handle the incoming data as if it were from a circular buffer - */ - - to = skb->data; - left = len; - - len2 = len; - while (len2 > 0) - { - amount = min(len2, (unsigned long) dev->rmem_end - - (unsigned long) buff); - memcpy(to, buff, amount); - len2 -= amount; - left -= amount; - buff += amount; - to += amount; - if ((unsigned long) buff == dev->rmem_end) - buff = (unsigned char *) dev->rmem_start; - } - } - - /* - * Tag the frame and kick it to the proper receive routine - */ - - skb->len = len; - skb->dev = dev; - skb->free = 1; - - netif_rx(skb); - /* - * OK, all done. - */ - return(0); -} - - -/* - * This routine causes all interfaces to try to send some data. - */ - -void dev_transmit(void) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->flags != 0 && !dev->tbusy) { - /* - * Kick the device - */ - dev_tint(dev); - } - } -} - - -/********************************************************************************** - - Receive Queue Processor - -***********************************************************************************/ - -/* - * This is a single non-reentrant routine which takes the received packet - * queue and throws it at the networking layers in the hope that something - * useful will emerge. - */ - -volatile char in_bh = 0; /* Non-reentrant remember */ - -int in_net_bh() /* Used by timer.c */ -{ - return(in_bh==0?0:1); -} - -/* - * When we are called the queue is ready to grab, the interrupts are - * on and hardware can interrupt and queue to the receive queue a we - * run with no problems. - * This is run as a bottom half after an interrupt handler that does - * mark_bh(NET_BH); - */ - -void net_bh(void *tmp) -{ - struct sk_buff *skb; - struct packet_type *ptype; - struct packet_type *pt_prev; - unsigned short type; - - /* - * Atomically check and mark our BUSY state. - */ - - if (set_bit(1, (void*)&in_bh)) - return; - - /* - * Can we send anything now? We want to clear the - * decks for any more sends that get done as we - * process the input. - */ - - dev_transmit(); - - /* - * Any data left to process. This may occur because a - * mark_bh() is done after we empty the queue including - * that from the device which does a mark_bh() just after - */ - - cli(); - - /* - * While the queue is not empty - */ - - while((skb=skb_dequeue(&backlog))!=NULL) - { - /* - * We have a packet. Therefore the queue has shrunk - */ - backlog_size--; - - sti(); - - /* - * Bump the pointer to the next structure. - * This assumes that the basic 'skb' pointer points to - * the MAC header, if any (as indicated by its "length" - * field). Take care now! - */ - - skb->h.raw = skb->data + skb->dev->hard_header_len; - skb->len -= skb->dev->hard_header_len; - - /* - * Fetch the packet protocol ID. This is also quite ugly, as - * it depends on the protocol driver (the interface itself) to - * know what the type is, or where to get it from. The Ethernet - * interfaces fetch the ID from the two bytes in the Ethernet MAC - * header (the h_proto field in struct ethhdr), but other drivers - * may either use the ethernet ID's or extra ones that do not - * clash (eg ETH_P_AX25). We could set this before we queue the - * frame. In fact I may change this when I have time. - */ - - type = skb->dev->type_trans(skb, skb->dev); - - /* - * We got a packet ID. Now loop over the "known protocols" - * table (which is actually a linked list, but this will - * change soon if I get my way- FvK), and forward the packet - * to anyone who wants it. - * - * [FvK didn't get his way but he is right this ought to be - * hashed so we typically get a single hit. The speed cost - * here is minimal but no doubt adds up at the 4,000+ pkts/second - * rate we can hit flat out] - */ - pt_prev = NULL; - for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) - { - if ((ptype->type == type || ptype->type == htons(ETH_P_ALL)) && (!ptype->dev || ptype->dev==skb->dev)) - { - /* - * We already have a match queued. Deliver - * to it and then remember the new match - */ - if(pt_prev) - { - struct sk_buff *skb2; - - skb2=skb_clone(skb, GFP_ATOMIC); - - /* - * Kick the protocol handler. This should be fast - * and efficient code. - */ - - if(skb2) - pt_prev->func(skb2, skb->dev, pt_prev); - } - /* Remember the current last to do */ - pt_prev=ptype; - } - } /* End of protocol list loop */ - - /* - * Is there a last item to send to ? - */ - - if(pt_prev) - pt_prev->func(skb, skb->dev, pt_prev); - /* - * Has an unknown packet has been received ? - */ - - else - kfree_skb(skb, FREE_WRITE); - - /* - * Again, see if we can transmit anything now. - * [Ought to take this out judging by tests it slows - * us down not speeds us up] - */ - - dev_transmit(); - cli(); - } /* End of queue loop */ - - /* - * We have emptied the queue - */ - - in_bh = 0; - sti(); - - /* - * One last output flush. - */ - - dev_transmit(); -} - - -/* - * This routine is called when an device driver (i.e. an - * interface) is ready to transmit a packet. - */ - -void dev_tint(struct device *dev) -{ - int i; - struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); - /* - * Work the queues in priority order - */ - - for(i = 0;i < DEV_NUMBUFFS; i++) - { - /* - * Pull packets from the queue - */ - - - cli(); - while((skb=skb_dequeue(&dev->buffs[i]))!=NULL) - { - /* - * Stop anyone freeing the buffer while we retransmit it - */ - skb_device_lock(skb); - restore_flags(flags); - /* - * Feed them to the output stage and if it fails - * indicate they re-queue at the front. - */ - dev_queue_xmit(skb,dev,-i - 1); - /* - * If we can take no more then stop here. - */ - if (dev->tbusy) - return; - cli(); - } - } - restore_flags(flags); -} - - -/* - * Perform a SIOCGIFCONF call. This structure will change - * size shortly, and there is nothing I can do about it. - * Thus we will need a 'compatibility mode'. - */ - -static int dev_ifconf(char *arg) -{ - struct ifconf ifc; - struct ifreq ifr; - struct device *dev; - char *pos; - int len; - int err; - - /* - * Fetch the caller's info block. - */ - - err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); - if(err) - return err; - memcpy_fromfs(&ifc, arg, sizeof(struct ifconf)); - len = ifc.ifc_len; - pos = ifc.ifc_buf; - - /* - * We now walk the device list filling each active device - * into the array. - */ - - err=verify_area(VERIFY_WRITE,pos,len); - if(err) - return err; - - /* - * Loop over the interfaces, and write an info block for each. - */ - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if(!(dev->flags & IFF_UP)) /* Downed devices don't count */ - continue; - memset(&ifr, 0, sizeof(struct ifreq)); - strcpy(ifr.ifr_name, dev->name); - (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; - (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; - - /* - * Write this block to the caller's space. - */ - - memcpy_tofs(pos, &ifr, sizeof(struct ifreq)); - pos += sizeof(struct ifreq); - len -= sizeof(struct ifreq); - - /* - * Have we run out of space here ? - */ - - if (len < sizeof(struct ifreq)) - break; - } - - /* - * All done. Write the updated control block back to the caller. - */ - - ifc.ifc_len = (pos - ifc.ifc_buf); - ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; - memcpy_tofs(arg, &ifc, sizeof(struct ifconf)); - - /* - * Report how much was filled in - */ - - return(pos - arg); -} - - -/* - * This is invoked by the /proc filesystem handler to display a device - * in detail. - */ - -static int sprintf_stats(char *buffer, struct device *dev) -{ - struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); - int size; - - if (stats) - size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", - dev->name, - stats->rx_packets, stats->rx_errors, - stats->rx_dropped + stats->rx_missed_errors, - stats->rx_fifo_errors, - stats->rx_length_errors + stats->rx_over_errors - + stats->rx_crc_errors + stats->rx_frame_errors, - stats->tx_packets, stats->tx_errors, stats->tx_dropped, - stats->tx_fifo_errors, stats->collisions, - stats->tx_carrier_errors + stats->tx_aborted_errors - + stats->tx_window_errors + stats->tx_heartbeat_errors); - else - size = sprintf(buffer, "%6s: No statistics available.\n", dev->name); - - return size; -} - -/* - * Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface - * to create /proc/net/dev - */ - -int dev_get_info(char *buffer, char **start, off_t offset, int length) -{ - int len=0; - off_t begin=0; - off_t pos=0; - int size; - - struct device *dev; - - - size = sprintf(buffer, "Inter-| Receive | Transmit\n" - " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); - - pos+=size; - len+=size; - - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - size = sprintf_stats(buffer+len, dev); - len+=size; - pos=begin+len; - - if(posoffset+length) - break; - } - - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len=length; /* Ending slop */ - return len; -} - - -/* - * This checks bitmasks for the ioctl calls for devices. - */ - -static inline int bad_mask(unsigned long mask, unsigned long addr) -{ - if (addr & (mask = ~mask)) - return 1; - mask = ntohl(mask); - if (mask & (mask+1)) - return 1; - return 0; -} - -#ifndef _HURD_ -/* - * Perform the SIOCxIFxxx calls. - * - * The socket layer has seen an ioctl the address family thinks is - * for the device. At this point we get invoked to make a decision - */ - -static int dev_ifsioc(void *arg, unsigned int getset) -{ - struct ifreq ifr; - struct device *dev; - int ret; - - /* - * Fetch the caller's info block into kernel space - */ - - int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); - if(err) - return err; - - memcpy_fromfs(&ifr, arg, sizeof(struct ifreq)); - - /* - * See which interface the caller is talking about. - */ - - if ((dev = dev_get(ifr.ifr_name)) == NULL) - return(-ENODEV); - - switch(getset) - { - case SIOCGIFFLAGS: /* Get interface flags */ - ifr.ifr_flags = dev->flags; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - case SIOCSIFFLAGS: /* Set interface flags */ - { - int old_flags = dev->flags; -#ifdef CONFIG_SLAVE_BALANCING - if(dev->flags&IFF_SLAVE) - return -EBUSY; -#endif - dev->flags = ifr.ifr_flags & ( - IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | - IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | - IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER - | IFF_MULTICAST); -#ifdef CONFIG_SLAVE_BALANCING - if(!(dev->flags&IFF_MASTER) && dev->slave) - { - dev->slave->flags&=~IFF_SLAVE; - dev->slave=NULL; - } -#endif - /* - * Load in the correct multicast list now the flags have changed. - */ - - dev_mc_upload(dev); -#if 0 - if( dev->set_multicast_list!=NULL) - { - - /* - * Has promiscuous mode been turned off - */ - - if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0)) - dev->set_multicast_list(dev,0,NULL); - - /* - * Has it been turned on - */ - - if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0)) - dev->set_multicast_list(dev,-1,NULL); - } -#endif - /* - * Have we downed the interface - */ - - if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) - { - ret = dev_close(dev); - } - else - { - /* - * Have we upped the interface - */ - - ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP)) - ? dev_open(dev) : 0; - /* - * Check the flags. - */ - if(ret<0) - dev->flags&=~IFF_UP; /* Didn't open so down the if */ - } - } - break; - - case SIOCGIFADDR: /* Get interface address (and family) */ - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - - case SIOCSIFADDR: /* Set interface address (and family) */ - dev->pa_addr = (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr; - dev->family = ifr.ifr_addr.sa_family; - -#ifdef CONFIG_INET - /* This is naughty. When net-032e comes out It wants moving into the net032 - code not the kernel. Till then it can sit here (SIGH) */ - dev->pa_mask = ip_get_mask(dev->pa_addr); -#endif - dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; - ret = 0; - break; - - case SIOCGIFBRDADDR: /* Get the broadcast address */ - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - - case SIOCSIFBRDADDR: /* Set the broadcast address */ - dev->pa_brdaddr = (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr; - ret = 0; - break; - - case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - - case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */ - dev->pa_dstaddr = (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr; - ret = 0; - break; - - case SIOCGIFNETMASK: /* Get the netmask for the interface */ - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_port = 0; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - - case SIOCSIFNETMASK: /* Set the netmask for the interface */ - { - unsigned long mask = (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr; - ret = -EINVAL; - /* - * The mask we set must be legal. - */ - if (bad_mask(mask,0)) - break; - dev->pa_mask = mask; - ret = 0; - } - break; - - case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ - - ifr.ifr_metric = dev->metric; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - - case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ - dev->metric = ifr.ifr_metric; - ret = 0; - break; - - case SIOCGIFMTU: /* Get the MTU of a device */ - ifr.ifr_mtu = dev->mtu; - memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); - ret = 0; - break; - - case SIOCSIFMTU: /* Set the MTU of a device */ - - /* - * MTU must be positive and under the page size problem - */ - - if(ifr.ifr_mtu<1 || ifr.ifr_mtu>3800) - return -EINVAL; - dev->mtu = ifr.ifr_mtu; - ret = 0; - break; - - case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently - do not support it */ - printk("NET: ioctl(SIOCGIFMEM, %p)\n", arg); - ret = -EINVAL; - break; - - case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ - printk("NET: ioctl(SIOCSIFMEM, %p)\n", arg); - ret = -EINVAL; - break; - - case OLD_SIOCGIFHWADDR: /* Get the hardware address. This will change and SIFHWADDR will be added */ - memcpy(ifr.old_ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN); - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - ret=0; - break; - - case SIOCGIFHWADDR: - memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); - ifr.ifr_hwaddr.sa_family=dev->type; - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - ret=0; - break; - - case SIOCSIFHWADDR: - if(dev->set_mac_address==NULL) - return -EOPNOTSUPP; - if(ifr.ifr_hwaddr.sa_family!=dev->type) - return -EINVAL; - ret=dev->set_mac_address(dev,ifr.ifr_hwaddr.sa_data); - break; - - case SIOCGIFMAP: - ifr.ifr_map.mem_start=dev->mem_start; - ifr.ifr_map.mem_end=dev->mem_end; - ifr.ifr_map.base_addr=dev->base_addr; - ifr.ifr_map.irq=dev->irq; - ifr.ifr_map.dma=dev->dma; - ifr.ifr_map.port=dev->if_port; - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - ret=0; - break; - - case SIOCSIFMAP: - if(dev->set_config==NULL) - return -EOPNOTSUPP; - return dev->set_config(dev,&ifr.ifr_map); - - case SIOCGIFSLAVE: -#ifdef CONFIG_SLAVE_BALANCING - if(dev->slave==NULL) - return -ENOENT; - strncpy(ifr.ifr_name,dev->name,sizeof(ifr.ifr_name)); - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - ret=0; -#else - return -ENOENT; -#endif - break; -#ifdef CONFIG_SLAVE_BALANCING - case SIOCSIFSLAVE: - { - - /* - * Fun game. Get the device up and the flags right without - * letting some scummy user confuse us. - */ - unsigned long flags; - struct device *slave=dev_get(ifr.ifr_slave); - save_flags(flags); - if(slave==NULL) - { - return -ENODEV; - } - cli(); - if((slave->flags&(IFF_UP|IFF_RUNNING))!=(IFF_UP|IFF_RUNNING)) - { - restore_flags(flags); - return -EINVAL; - } - if(dev->flags&IFF_SLAVE) - { - restore_flags(flags); - return -EBUSY; - } - if(dev->slave!=NULL) - { - restore_flags(flags); - return -EBUSY; - } - if(slave->flags&IFF_SLAVE) - { - restore_flags(flags); - return -EBUSY; - } - dev->slave=slave; - slave->flags|=IFF_SLAVE; - dev->flags|=IFF_MASTER; - restore_flags(flags); - ret=0; - } - break; -#endif - - case SIOCADDMULTI: - if(dev->set_multicast_list==NULL) - return -EINVAL; - if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) - return -EINVAL; - dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1); - return 0; - - case SIOCDELMULTI: - if(dev->set_multicast_list==NULL) - return -EINVAL; - if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) - return -EINVAL; - dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1); - return 0; - /* - * Unknown or private ioctl - */ - - default: - if((getset >= SIOCDEVPRIVATE) && - (getset <= (SIOCDEVPRIVATE + 15))) { - if(dev->do_ioctl==NULL) - return -EOPNOTSUPP; - ret=dev->do_ioctl(dev, &ifr, getset); - memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); - break; - } - - ret = -EINVAL; - } - return(ret); -} - - -/* - * This function handles all "interface"-type I/O control requests. The actual - * 'doing' part of this is dev_ifsioc above. - */ - -int dev_ioctl(unsigned int cmd, void *arg) -{ - switch(cmd) - { - case SIOCGIFCONF: - (void) dev_ifconf((char *) arg); - return 0; - - /* - * Ioctl calls that can be done by all. - */ - - case SIOCGIFFLAGS: - case SIOCGIFADDR: - case SIOCGIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFMEM: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case OLD_SIOCGIFHWADDR: - case SIOCGIFSLAVE: - case SIOCGIFMAP: - return dev_ifsioc(arg, cmd); - - /* - * Ioctl calls requiring the power of a superuser - */ - - case SIOCSIFFLAGS: - case SIOCSIFADDR: - case SIOCSIFDSTADDR: - case SIOCSIFBRDADDR: - case SIOCSIFNETMASK: - case SIOCSIFMETRIC: - case SIOCSIFMTU: - case SIOCSIFMEM: - case SIOCSIFMAP: - case SIOCSIFSLAVE: - case SIOCADDMULTI: - case SIOCDELMULTI: - if (!suser()) - return -EPERM; - return dev_ifsioc(arg, cmd); - - case SIOCSIFLINK: - return -EINVAL; - - /* - * Unknown or private ioctl. - */ - - default: - if((cmd >= SIOCDEVPRIVATE) && - (cmd <= (SIOCDEVPRIVATE + 15))) { - return dev_ifsioc(arg, cmd); - } - return -EINVAL; - } -} -#endif - - -/* - * Initialize the DEV module. At boot time this walks the device list and - * unhooks any devices that fail to initialise (normally hardware not - * present) and leaves us with a valid list of present and active devices. - * - * The PCMCIA code may need to change this a little, and add a pair - * of register_inet_device() unregister_inet_device() calls. This will be - * needed for ethernet as modules support. - */ - -void dev_init(void) -{ - struct device *dev, *dev2; - - /* - * Add the devices. - * If the call to dev->init fails, the dev is removed - * from the chain disconnecting the device until the - * next reboot. - */ - - dev2 = NULL; - for (dev = dev_base; dev != NULL; dev=dev->next) - { - if (dev->init && dev->init(dev)) - { - /* - * It failed to come up. Unhook it. - */ - - if (dev2 == NULL) - dev_base = dev->next; - else - dev2->next = dev->next; - } - else - { - dev2 = dev; - } - } -} diff --git a/pfinet/linux-inet/dev_mcast.c b/pfinet/linux-inet/dev_mcast.c deleted file mode 100644 index cd5e356e..00000000 --- a/pfinet/linux-inet/dev_mcast.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Linux NET3: Multicast List maintenance. - * - * Authors: - * Tim Kordas - * Richard Underwood - * - * Stir fried together from the IP multicast and CAP patches above - * Alan Cox - * - * Fixes: - * Alan Cox : Update the device on a real delete - * rather than any time but... - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "route.h" -#include -#include "sock.h" -#include "arp.h" - - -/* - * Device multicast list maintenance. This knows about such little matters as promiscuous mode and - * converting from the list to the array the drivers use. At least until I fix the drivers up. - * - * This is used both by IP and by the user level maintenance functions. Unlike BSD we maintain a usage count - * on a given multicast address so that a casual user application can add/delete multicasts used by protocols - * without doing damage to the protocols when it deletes the entries. It also helps IP as it tracks overlapping - * maps. - */ - - -/* - * Update the multicast list into the physical NIC controller. - */ - -void dev_mc_upload(struct device *dev) -{ - struct dev_mc_list *dmi; - char *data, *tmp; - - /* Don't do anything till we up the interface - [dev_open will call this function so the list will - stay sane] */ - - if(!(dev->flags&IFF_UP)) - return; - - - /* Devices with no set multicast don't get set */ - if(dev->set_multicast_list==NULL) - return; - /* Promiscuous is promiscuous - so no filter needed */ - if(dev->flags&IFF_PROMISC) - { - dev->set_multicast_list(dev, -1, NULL); - return; - } - - if(dev->mc_count==0) - { - dev->set_multicast_list(dev,0,NULL); - return; - } - - data=kmalloc(dev->mc_count*dev->addr_len, GFP_KERNEL); - if(data==NULL) - { - printk("Unable to get memory to set multicast list on %s\n",dev->name); - return; - } - for(tmp = data, dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) - { - memcpy(tmp,dmi->dmi_addr, dmi->dmi_addrlen); - tmp+=dev->addr_len; - } - dev->set_multicast_list(dev,dev->mc_count,data); - kfree(data); -} - -/* - * Delete a device level multicast - */ - -void dev_mc_delete(struct device *dev, void *addr, int alen, int all) -{ - struct dev_mc_list **dmi; - for(dmi=&dev->mc_list;*dmi!=NULL;dmi=&(*dmi)->next) - { - if(memcmp((*dmi)->dmi_addr,addr,(*dmi)->dmi_addrlen)==0 && alen==(*dmi)->dmi_addrlen) - { - struct dev_mc_list *tmp= *dmi; - if(--(*dmi)->dmi_users && !all) - return; - *dmi=(*dmi)->next; - dev->mc_count--; - kfree_s(tmp,sizeof(*tmp)); - dev_mc_upload(dev); - return; - } - } -} - -/* - * Add a device level multicast - */ - -void dev_mc_add(struct device *dev, void *addr, int alen, int newonly) -{ - struct dev_mc_list *dmi; - for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) - { - if(memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) - { - if(!newonly) - dmi->dmi_users++; - return; - } - } - dmi=(struct dev_mc_list *)kmalloc(sizeof(*dmi),GFP_KERNEL); - if(dmi==NULL) - return; /* GFP_KERNEL so can't happen anyway */ - memcpy(dmi->dmi_addr, addr, alen); - dmi->dmi_addrlen=alen; - dmi->next=dev->mc_list; - dmi->dmi_users=1; - dev->mc_list=dmi; - dev->mc_count++; - dev_mc_upload(dev); -} - -/* - * Discard multicast list when a device is downed - */ - -void dev_mc_discard(struct device *dev) -{ - while(dev->mc_list!=NULL) - { - struct dev_mc_list *tmp=dev->mc_list; - dev->mc_list=dev->mc_list->next; - kfree_s(tmp,sizeof(*tmp)); - } - dev->mc_count=0; -} - diff --git a/pfinet/linux-inet/devinet.c b/pfinet/linux-inet/devinet.c deleted file mode 100644 index 946536be..00000000 --- a/pfinet/linux-inet/devinet.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * NET3 IP device support routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Derived from the IP parts of dev.c 1.0.19 - * Authors: Ross Biro, - * Fred N. van Kempen, - * Mark Evans, - * - * Additional Authors: - * Alan Cox, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "route.h" -#include "protocol.h" -#include "tcp.h" -#include -#include "sock.h" -#include "arp.h" - -/* - * Determine a default network mask, based on the IP address. - */ - -unsigned long ip_get_mask(unsigned long addr) -{ - unsigned long dst; - - if (addr == 0L) - return(0L); /* special case */ - - dst = ntohl(addr); - if (IN_CLASSA(dst)) - return(htonl(IN_CLASSA_NET)); - if (IN_CLASSB(dst)) - return(htonl(IN_CLASSB_NET)); - if (IN_CLASSC(dst)) - return(htonl(IN_CLASSC_NET)); - - /* - * Something else, probably a multicast. - */ - - return(0); -} - -/* - * Check the address for our address, broadcasts, etc. - * - * I intend to fix this to at the very least cache the last - * resolved entry. - */ - -int ip_chk_addr(unsigned long addr) -{ - struct device *dev; - unsigned long mask; - - /* - * Accept both `all ones' and `all zeros' as BROADCAST. - * (Support old BSD in other words). This old BSD - * support will go very soon as it messes other things - * up. - * Also accept `loopback broadcast' as BROADCAST. - */ - - if (addr == INADDR_ANY || addr == INADDR_BROADCAST || - addr == htonl(0x7FFFFFFFL)) - return IS_BROADCAST; - - mask = ip_get_mask(addr); - - /* - * Accept all of the `loopback' class A net. - */ - - if ((addr & mask) == htonl(0x7F000000L)) - return IS_MYADDR; - - /* - * OK, now check the interface addresses. - */ - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (!(dev->flags & IFF_UP)) - continue; - /* - * If the protocol address of the device is 0 this is special - * and means we are address hunting (eg bootp). - */ - - if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/) - return IS_MYADDR; - /* - * Is it the exact IP address? - */ - - if (addr == dev->pa_addr) - return IS_MYADDR; - /* - * Is it our broadcast address? - */ - - if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr) - return IS_BROADCAST; - /* - * Nope. Check for a subnetwork broadcast. - */ - - if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0) - { - if ((addr & ~dev->pa_mask) == 0) - return IS_BROADCAST; - if ((addr & ~dev->pa_mask) == ~dev->pa_mask) - return IS_BROADCAST; - } - - /* - * Nope. Check for Network broadcast. - */ - - if (((addr ^ dev->pa_addr) & mask) == 0) - { - if ((addr & ~mask) == 0) - return IS_BROADCAST; - if ((addr & ~mask) == ~mask) - return IS_BROADCAST; - } - } - if(IN_MULTICAST(ntohl(addr))) - return IS_MULTICAST; - return 0; /* no match at all */ -} - - -/* - * Retrieve our own address. - * - * Because the loopback address (127.0.0.1) is already recognized - * automatically, we can use the loopback interface's address as - * our "primary" interface. This is the address used by IP et - * al when it doesn't know which address to use (i.e. it does not - * yet know from or to which interface to go...). - */ - -unsigned long ip_my_addr(void) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->flags & IFF_LOOPBACK) - return(dev->pa_addr); - } - return(0); -} - -/* - * Find an interface that can handle addresses for a certain address. - * - * This needs optimising, since it's relatively trivial to collapse - * the two loops into one. - */ - -struct device * ip_dev_check(unsigned long addr) -{ - struct device *dev; - - for (dev = dev_base; dev; dev = dev->next) - { - if (!(dev->flags & IFF_UP)) - continue; - if (!(dev->flags & IFF_POINTOPOINT)) - continue; - if (addr != dev->pa_dstaddr) - continue; - return dev; - } - for (dev = dev_base; dev; dev = dev->next) - { - if (!(dev->flags & IFF_UP)) - continue; - if (dev->flags & IFF_POINTOPOINT) - continue; - if (dev->pa_mask & (addr ^ dev->pa_addr)) - continue; - return dev; - } - return NULL; -} diff --git a/pfinet/linux-inet/eth.c b/pfinet/linux-inet/eth.c deleted file mode 100644 index cbd2c94b..00000000 --- a/pfinet/linux-inet/eth.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Ethernet-type device handling. - * - * Version: @(#)eth.c 1.0.7 05/25/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Mark Evans, - * Florian La Roche, - * Alan Cox, - * - * Fixes: - * Mr Linux : Arp problems - * Alan Cox : Generic queue tidyup (very tiny here) - * Alan Cox : eth_header ntohs should be htons - * Alan Cox : eth_rebuild_header missing an htons and - * minor other things. - * Tegge : Arp bug fixes. - * Florian : Removed many unnecessary functions, code cleanup - * and changes for new arp and skbuff. - * Alan Cox : Redid header building to reflect new format. - * Alan Cox : ARP only when compiled with CONFIG_INET - * Greg Page : 802.2 and SNAP stuff - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "arp.h" - -void eth_setup(char *str, int *ints) -{ - struct device *d = dev_base; - - if (!str || !*str) - return; - while (d) - { - if (!strcmp(str,d->name)) - { - if (ints[0] > 0) - d->irq=ints[1]; - if (ints[0] > 1) - d->base_addr=ints[2]; - if (ints[0] > 2) - d->mem_start=ints[3]; - if (ints[0] > 3) - d->mem_end=ints[4]; - break; - } - d=d->next; - } -} - - -/* - * Create the Ethernet MAC header for an arbitrary protocol layer - * - * saddr=NULL means use device source address - * daddr=NULL means leave destination address (eg unresolved arp) - */ - -int eth_header(unsigned char *buff, struct device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len, - struct sk_buff *skb) -{ - struct ethhdr *eth = (struct ethhdr *)buff; - - /* - * Set the protocol type. For a packet of type ETH_P_802_3 we put the length - * in here instead. It is up to the 802.2 layer to carry protocol information. - */ - - if(type!=ETH_P_802_3) - eth->h_proto = htons(type); - else - eth->h_proto = htons(len); - - /* - * Set the source hardware address. - */ - - if(saddr) - memcpy(eth->h_source,saddr,dev->addr_len); - else - memcpy(eth->h_source,dev->dev_addr,dev->addr_len); - - /* - * Anyway, the loopback-device should never use this function... - */ - - if (dev->flags & IFF_LOOPBACK) - { - memset(eth->h_dest, 0, dev->addr_len); - return(dev->hard_header_len); - } - - if(daddr) - { - memcpy(eth->h_dest,daddr,dev->addr_len); - return dev->hard_header_len; - } - - return -dev->hard_header_len; -} - - -/* - * Rebuild the Ethernet MAC header. This is called after an ARP - * (or in future other address resolution) has completed on this - * sk_buff. We now let ARP fill in the other fields. - */ - -int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst, - struct sk_buff *skb) -{ - struct ethhdr *eth = (struct ethhdr *)buff; - - /* - * Only ARP/IP is currently supported - */ - - if(eth->h_proto != htons(ETH_P_IP)) - { - printk("eth_rebuild_header: Don't know how to resolve type %d addresses?\n",(int)eth->h_proto); - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - return 0; - } - - /* - * Try and get ARP to resolve the header. - */ -#ifdef CONFIG_INET - return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; -#else - return 0; -#endif -} - - -/* - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - */ - -unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) -{ - struct ethhdr *eth = (struct ethhdr *) skb->data; - unsigned char *rawp; - - if(*eth->h_dest&1) - { - if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) - skb->pkt_type=PACKET_BROADCAST; - else - skb->pkt_type=PACKET_MULTICAST; - } - - if(dev->flags&IFF_PROMISC) - { - if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN)) - skb->pkt_type=PACKET_OTHERHOST; - } - - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - - rawp = (unsigned char *)(eth + 1); - - if (*(unsigned short *)rawp == 0xFFFF) - return htons(ETH_P_802_3); - - return htons(ETH_P_802_2); -} diff --git a/pfinet/linux-inet/eth.h b/pfinet/linux-inet/eth.h deleted file mode 100644 index f8fed44e..00000000 --- a/pfinet/linux-inet/eth.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. NET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Ethernet handlers. - * - * Version: @(#)eth.h 1.0.4 05/13/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _ETH_H -#define _ETH_H - - -#include - - -extern char *eth_print(unsigned char *ptr); -extern void eth_dump(struct ethhdr *eth); -extern int eth_header(unsigned char *buff, struct device *dev, - unsigned short type, unsigned long daddr, - unsigned long saddr, unsigned len); -extern int eth_rebuild_header(void *buff, struct device *dev); -extern void eth_add_arp(unsigned long addr, struct sk_buff *skb, - struct device *dev); -extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev); - -#endif /* _ETH_H */ diff --git a/pfinet/linux-inet/icmp.c b/pfinet/linux-inet/icmp.c deleted file mode 100644 index c023eab2..00000000 --- a/pfinet/linux-inet/icmp.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Internet Control Message Protocol (ICMP) - * - * Version: @(#)icmp.c 1.0.11 06/02/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Mark Evans, - * Alan Cox, - * Stefan Becker, - * - * Fixes: - * Alan Cox : Generic queue usage. - * Gerhard Koerting: ICMP addressing corrected - * Alan Cox : Use tos/ttl settings - * Alan Cox : Protocol violations - * Alan Cox : SNMP Statistics - * Alan Cox : Routing errors - * Alan Cox : Changes for newer routing code - * Alan Cox : Removed old debugging junk - * Alan Cox : Fixed the ICMP error status of net/host unreachable - * Gerhard Koerting : Fixed broadcast ping properly - * Ulrich Kunitz : Fixed ICMP timestamp reply - * A.N.Kuznetsov : Multihoming fixes. - * Laco Rusnak : Multihoming fixes. - * Alan Cox : Tightened up icmp_send(). - * Alan Cox : Multicasts. - * Stefan Becker : ICMP redirects in icmp_send(). - * - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "snmp.h" -#include "ip.h" -#include "route.h" -#include "protocol.h" -#include "icmp.h" -#include "tcp.h" -#include "snmp.h" -#include -#include "sock.h" -#include -#include -#include -#include - - -#define min(a,b) ((a)<(b)?(a):(b)) - - -/* - * Statistics - */ - -struct icmp_mib icmp_statistics={0,}; - - -/* An array of errno for error messages from dest unreach. */ -struct icmp_err icmp_err_convert[] = { - { ENETUNREACH, 0 }, /* ICMP_NET_UNREACH */ - { EHOSTUNREACH, 0 }, /* ICMP_HOST_UNREACH */ - { ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */ - { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */ - { EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */ - { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */ - { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */ - { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */ - { ENONET, 1 }, /* ICMP_HOST_ISOLATED */ - { ENETUNREACH, 1 }, /* ICMP_NET_ANO */ - { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */ - { EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS */ - { EOPNOTSUPP, 0 } /* ICMP_HOST_UNR_TOS */ -}; - - -/* - * Send an ICMP message in response to a situation - * - * Fixme: Fragment handling is wrong really. - */ - -void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev) -{ - struct sk_buff *skb; - struct iphdr *iph; - int offset; - struct icmphdr *icmph; - int len; - struct device *ndev=NULL; /* Make this =dev to force replies on the same interface */ - unsigned long our_addr; - int atype; - - /* - * Find the original IP header. - */ - - iph = (struct iphdr *) (skb_in->data + dev->hard_header_len); - - /* - * No replies to MAC multicast - */ - - if(skb_in->pkt_type!=PACKET_HOST) - return; - - /* - * No replies to IP multicasting - */ - - atype=ip_chk_addr(iph->daddr); - if(atype==IS_BROADCAST || IN_MULTICAST(iph->daddr)) - return; - - /* - * Only reply to first fragment. - */ - - if(ntohs(iph->frag_off)&IP_OFFSET) - return; - - /* - * We must NEVER NEVER send an ICMP error to an ICMP error message - */ - - if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED) - { - - /* - * Is the original packet an ICMP packet? - */ - - if(iph->protocol==IPPROTO_ICMP) - { - icmph = (struct icmphdr *) ((char *) iph + - 4 * iph->ihl); - /* - * Check for ICMP error packets (Must never reply to - * an ICMP error). - */ - - if (icmph->type == ICMP_DEST_UNREACH || - icmph->type == ICMP_SOURCE_QUENCH || - icmph->type == ICMP_REDIRECT || - icmph->type == ICMP_TIME_EXCEEDED || - icmph->type == ICMP_PARAMETERPROB) - return; - } - } - icmp_statistics.IcmpOutMsgs++; - - /* - * This needs a tidy. - */ - - switch(type) - { - case ICMP_DEST_UNREACH: - icmp_statistics.IcmpOutDestUnreachs++; - break; - case ICMP_SOURCE_QUENCH: - icmp_statistics.IcmpOutSrcQuenchs++; - break; - case ICMP_REDIRECT: - icmp_statistics.IcmpOutRedirects++; - break; - case ICMP_ECHO: - icmp_statistics.IcmpOutEchos++; - break; - case ICMP_ECHOREPLY: - icmp_statistics.IcmpOutEchoReps++; - break; - case ICMP_TIME_EXCEEDED: - icmp_statistics.IcmpOutTimeExcds++; - break; - case ICMP_PARAMETERPROB: - icmp_statistics.IcmpOutParmProbs++; - break; - case ICMP_TIMESTAMP: - icmp_statistics.IcmpOutTimestamps++; - break; - case ICMP_TIMESTAMPREPLY: - icmp_statistics.IcmpOutTimestampReps++; - break; - case ICMP_ADDRESS: - icmp_statistics.IcmpOutAddrMasks++; - break; - case ICMP_ADDRESSREPLY: - icmp_statistics.IcmpOutAddrMaskReps++; - break; - } - /* - * Get some memory for the reply. - */ - - len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) + - sizeof(struct iphdr) + 32; /* amount of header to return */ - - skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC); - if (skb == NULL) - { - icmp_statistics.IcmpOutErrors++; - return; - } - skb->free = 1; - - /* - * Build Layer 2-3 headers for message back to source. - */ - - our_addr = dev->pa_addr; - if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR) - our_addr = iph->daddr; - offset = ip_build_header(skb, our_addr, iph->saddr, - &ndev, IPPROTO_ICMP, NULL, len, - skb_in->ip_hdr->tos,255); - if (offset < 0) - { - icmp_statistics.IcmpOutErrors++; - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return; - } - - /* - * Re-adjust length according to actual IP header size. - */ - - skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8; - - /* - * Fill in the frame - */ - - icmph = (struct icmphdr *) (skb->data + offset); - icmph->type = type; - icmph->code = code; - icmph->checksum = 0; - icmph->un.gateway = info; /* This might not be meant for - this form of the union but it will - be right anyway */ - memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8); - - icmph->checksum = ip_compute_csum((unsigned char *)icmph, - sizeof(struct icmphdr) + sizeof(struct iphdr) + 8); - - /* - * Send it and free it once sent. - */ - ip_queue_xmit(NULL, ndev, skb, 1); -} - - -/* - * Handle ICMP_UNREACH and ICMP_QUENCH. - */ - -static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) -{ - struct inet_protocol *ipprot; - struct iphdr *iph; - unsigned char hash; - int err; - - err = (icmph->type << 8) | icmph->code; - iph = (struct iphdr *) (icmph + 1); - - switch(icmph->code & 7) - { - case ICMP_NET_UNREACH: - break; - case ICMP_HOST_UNREACH: - break; - case ICMP_PROT_UNREACH: - printk("ICMP: %s:%d: protocol unreachable.\n", - in_ntoa(iph->daddr), ntohs(iph->protocol)); - break; - case ICMP_PORT_UNREACH: - break; - case ICMP_FRAG_NEEDED: - printk("ICMP: %s: fragmentation needed and DF set.\n", - in_ntoa(iph->daddr)); - break; - case ICMP_SR_FAILED: - printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr)); - break; - default: - break; - } - - /* - * Get the protocol(s). - */ - - hash = iph->protocol & (MAX_INET_PROTOS -1); - - /* - * This can't change while we are doing it. - */ - - ipprot = (struct inet_protocol *) inet_protos[hash]; - while(ipprot != NULL) - { - struct inet_protocol *nextip; - - nextip = (struct inet_protocol *) ipprot->next; - - /* - * Pass it off to everyone who wants it. - */ - if (iph->protocol == ipprot->protocol && ipprot->err_handler) - { - ipprot->err_handler(err, (unsigned char *)(icmph + 1), - iph->daddr, iph->saddr, ipprot); - } - - ipprot = nextip; - } - kfree_skb(skb, FREE_READ); -} - - -/* - * Handle ICMP_REDIRECT. - */ - -static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, - struct device *dev, unsigned long source) -{ - struct rtable *rt; - struct iphdr *iph; - unsigned long ip; - - /* - * Get the copied header of the packet that caused the redirect - */ - - iph = (struct iphdr *) (icmph + 1); - ip = iph->daddr; - - switch(icmph->code & 7) - { - case ICMP_REDIR_NET: - /* - * This causes a problem with subnetted networks. What we should do - * is use ICMP_ADDRESS to get the subnet mask of the problem route - * and set both. But we don't.. - */ -#ifdef not_a_good_idea - ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev,0, 0); - break; -#endif - case ICMP_REDIR_HOST: - /* - * Add better route to host. - * But first check that the redirect - * comes from the old gateway.. - * And make sure it's an ok host address - * (not some confused thing sending our - * address) - */ - rt = ip_rt_route(ip, NULL, NULL); - if (!rt) - break; - if (rt->rt_gateway != source || ip_chk_addr(icmph->un.gateway)) - break; - printk("redirect from %s\n", in_ntoa(source)); - ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev,0, 0); - break; - case ICMP_REDIR_NETTOS: - case ICMP_REDIR_HOSTTOS: - printk("ICMP: cannot handle TOS redirects yet!\n"); - break; - default: - break; - } - - /* - * Discard the original packet - */ - - kfree_skb(skb, FREE_READ); -} - - -/* - * Handle ICMP_ECHO ("ping") requests. - */ - -static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, - unsigned long saddr, unsigned long daddr, int len, - struct options *opt) -{ - struct icmphdr *icmphr; - struct sk_buff *skb2; - struct device *ndev=NULL; - int size, offset; - - icmp_statistics.IcmpOutEchoReps++; - icmp_statistics.IcmpOutMsgs++; - - size = dev->hard_header_len + 64 + len; - skb2 = alloc_skb(size, GFP_ATOMIC); - - if (skb2 == NULL) - { - icmp_statistics.IcmpOutErrors++; - kfree_skb(skb, FREE_READ); - return; - } - skb2->free = 1; - - /* Build Layer 2-3 headers for message back to source */ - offset = ip_build_header(skb2, daddr, saddr, &ndev, - IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255); - if (offset < 0) - { - icmp_statistics.IcmpOutErrors++; - printk("ICMP: Could not build IP Header for ICMP ECHO Response\n"); - kfree_skb(skb2,FREE_WRITE); - kfree_skb(skb, FREE_READ); - return; - } - - /* - * Re-adjust length according to actual IP header size. - */ - - skb2->len = offset + len; - - /* - * Build ICMP_ECHO Response message. - */ - icmphr = (struct icmphdr *) (skb2->data + offset); - memcpy((char *) icmphr, (char *) icmph, len); - icmphr->type = ICMP_ECHOREPLY; - icmphr->code = 0; - icmphr->checksum = 0; - icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len); - - /* - * Ship it out - free it when done - */ - ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1); - - /* - * Free the received frame - */ - - kfree_skb(skb, FREE_READ); -} - -/* - * Handle ICMP Timestamp requests. - */ - -static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, - unsigned long saddr, unsigned long daddr, int len, - struct options *opt) -{ - struct icmphdr *icmphr; - struct sk_buff *skb2; - int size, offset; - unsigned long *timeptr, midtime; - struct device *ndev=NULL; - - if (len != 20) - { - printk( - "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n", - len); - icmp_statistics.IcmpInErrors++; -#if 1 - /* correct answers are possible for everything >= 12 */ - if (len < 12) -#endif - return; - } - - size = dev->hard_header_len + 84; - - if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) - { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - icmp_statistics.IcmpOutErrors++; - return; - } - skb2->free = 1; - -/* - * Build Layer 2-3 headers for message back to source - */ - - offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, - skb->ip_hdr->tos, 255); - if (offset < 0) - { - printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n"); - kfree_skb(skb2, FREE_WRITE); - kfree_skb(skb, FREE_READ); - icmp_statistics.IcmpOutErrors++; - return; - } - - /* - * Re-adjust length according to actual IP header size. - */ - skb2->len = offset + 20; - - /* - * Build ICMP_TIMESTAMP Response message. - */ - - icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset); - memcpy((char *) icmphr, (char *) icmph, 12); - icmphr->type = ICMP_TIMESTAMPREPLY; - icmphr->code = icmphr->checksum = 0; - - /* fill in the current time as ms since midnight UT: */ - midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000; - timeptr = (unsigned long *) (icmphr + 1); - /* - * the originate timestamp (timeptr [0]) is still in the copy: - */ - timeptr [1] = timeptr [2] = htonl(midtime); - - icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20); - - /* - * Ship it out - free it when done - */ - - ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1); - icmp_statistics.IcmpOutTimestampReps++; - kfree_skb(skb, FREE_READ); -} - - - - -/* - * Handle the ICMP INFORMATION REQUEST. - */ - -static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, - unsigned long saddr, unsigned long daddr, int len, - struct options *opt) -{ - /* Obsolete */ - kfree_skb(skb, FREE_READ); -} - - -/* - * Handle ICMP_ADDRESS_MASK requests. - */ - -static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, - unsigned long saddr, unsigned long daddr, int len, - struct options *opt) -{ - struct icmphdr *icmphr; - struct sk_buff *skb2; - int size, offset; - struct device *ndev=NULL; - - icmp_statistics.IcmpOutMsgs++; - icmp_statistics.IcmpOutAddrMaskReps++; - - size = dev->hard_header_len + 64 + len; - skb2 = alloc_skb(size, GFP_ATOMIC); - if (skb2 == NULL) - { - icmp_statistics.IcmpOutErrors++; - kfree_skb(skb, FREE_READ); - return; - } - skb2->free = 1; - - /* - * Build Layer 2-3 headers for message back to source - */ - - offset = ip_build_header(skb2, daddr, saddr, &ndev, - IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255); - if (offset < 0) - { - icmp_statistics.IcmpOutErrors++; - printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n"); - kfree_skb(skb2,FREE_WRITE); - kfree_skb(skb, FREE_READ); - return; - } - - /* - * Re-adjust length according to actual IP header size. - */ - - skb2->len = offset + len; - - /* - * Build ICMP ADDRESS MASK Response message. - */ - - icmphr = (struct icmphdr *) (skb2->data + offset); - icmphr->type = ICMP_ADDRESSREPLY; - icmphr->code = 0; - icmphr->checksum = 0; - icmphr->un.echo.id = icmph->un.echo.id; - icmphr->un.echo.sequence = icmph->un.echo.sequence; - memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask)); - - icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len); - - /* Ship it out - free it when done */ - ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1); - - skb->sk = NULL; - kfree_skb(skb, FREE_READ); -} - - -/* - * Deal with incoming ICMP packets. - */ - -int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, - unsigned long daddr, unsigned short len, - unsigned long saddr, int redo, struct inet_protocol *protocol) -{ - struct icmphdr *icmph; - unsigned char *buff; - - /* - * Drop broadcast packets. IP has done a broadcast check and ought one day - * to pass on that information. - */ - - icmp_statistics.IcmpInMsgs++; - - - /* - * Grab the packet as an icmp object - */ - - buff = skb1->h.raw; - icmph = (struct icmphdr *) buff; - - /* - * Validate the packet first - */ - - if (ip_compute_csum((unsigned char *) icmph, len)) - { - /* Failed checksum! */ - icmp_statistics.IcmpInErrors++; - printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr)); - kfree_skb(skb1, FREE_READ); - return(0); - } - - /* - * Parse the ICMP message - */ - - if (ip_chk_addr(daddr) != IS_MYADDR) - { - if (icmph->type != ICMP_ECHO) - { - icmp_statistics.IcmpInErrors++; - kfree_skb(skb1, FREE_READ); - return(0); - } - daddr=dev->pa_addr; - } - - switch(icmph->type) - { - case ICMP_TIME_EXCEEDED: - icmp_statistics.IcmpInTimeExcds++; - icmp_unreach(icmph, skb1); - return 0; - case ICMP_DEST_UNREACH: - icmp_statistics.IcmpInDestUnreachs++; - icmp_unreach(icmph, skb1); - return 0; - case ICMP_SOURCE_QUENCH: - icmp_statistics.IcmpInSrcQuenchs++; - icmp_unreach(icmph, skb1); - return(0); - case ICMP_REDIRECT: - icmp_statistics.IcmpInRedirects++; - icmp_redirect(icmph, skb1, dev, saddr); - return(0); - case ICMP_ECHO: - icmp_statistics.IcmpInEchos++; - icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_ECHOREPLY: - icmp_statistics.IcmpInEchoReps++; - kfree_skb(skb1, FREE_READ); - return(0); - case ICMP_TIMESTAMP: - icmp_statistics.IcmpInTimestamps++; - icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_TIMESTAMPREPLY: - icmp_statistics.IcmpInTimestampReps++; - kfree_skb(skb1,FREE_READ); - return 0; - /* INFO is obsolete and doesn't even feature in the SNMP stats */ - case ICMP_INFO_REQUEST: - icmp_info(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_INFO_REPLY: - skb1->sk = NULL; - kfree_skb(skb1, FREE_READ); - return(0); - case ICMP_ADDRESS: - icmp_statistics.IcmpInAddrMasks++; - icmp_address(icmph, skb1, dev, saddr, daddr, len, opt); - return 0; - case ICMP_ADDRESSREPLY: - /* - * We ought to set our netmask on receiving this, but - * experience shows it's a waste of effort. - */ - icmp_statistics.IcmpInAddrMaskReps++; - kfree_skb(skb1, FREE_READ); - return(0); - default: - icmp_statistics.IcmpInErrors++; - kfree_skb(skb1, FREE_READ); - return(0); - } - /*NOTREACHED*/ - kfree_skb(skb1, FREE_READ); - return(-1); -} - - -/* - * Perform any ICMP-related I/O control requests. - * [to vanish soon] - */ - -int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - switch(cmd) - { - default: - return(-EINVAL); - } - return(0); -} diff --git a/pfinet/linux-inet/icmp.h b/pfinet/linux-inet/icmp.h deleted file mode 100644 index 8f1c3498..00000000 --- a/pfinet/linux-inet/icmp.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the ICMP module. - * - * Version: @(#)icmp.h 1.0.4 05/13/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _ICMP_H -#define _ICMP_H - -#include - - -extern struct icmp_err icmp_err_convert[]; -extern struct icmp_mib icmp_statistics; - - -extern void icmp_send(struct sk_buff *skb_in, int type, int code, - unsigned long info, struct device *dev); -extern int icmp_rcv(struct sk_buff *skb1, struct device *dev, - struct options *opt, unsigned long daddr, - unsigned short len, unsigned long saddr, - int redo, struct inet_protocol *protocol); - -extern int icmp_ioctl(struct sock *sk, int cmd, - unsigned long arg); - -#endif /* _ICMP_H */ diff --git a/pfinet/linux-inet/igmp.c b/pfinet/linux-inet/igmp.c deleted file mode 100644 index 32e42213..00000000 --- a/pfinet/linux-inet/igmp.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Linux NET3: Internet Gateway Management Protocol [IGMP] - * - * Authors: - * Alan Cox - * - * WARNING: - * This is a 'preliminary' implementation... on your own head - * be it. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include "route.h" -#include -#include "sock.h" -#include - -#ifdef CONFIG_IP_MULTICAST - - -/* - * Timer management - */ - - -static void igmp_stop_timer(struct ip_mc_list *im) -{ - del_timer(&im->timer); - im->tm_running=0; -} - -static int igmp_random(void) -{ - static unsigned long seed=152L; - seed=seed*69069L+1; - return seed^jiffies; -} - - -static void igmp_start_timer(struct ip_mc_list *im) -{ - int tv; - if(im->tm_running) - return; - tv=igmp_random()%(10*HZ); /* Pick a number any number 8) */ - im->timer.expires=tv; - im->tm_running=1; - add_timer(&im->timer); -} - -/* - * Send an IGMP report. - */ - -#define MAX_IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+64) - -static void igmp_send_report(struct device *dev, unsigned long address, int type) -{ - struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC); - int tmp; - struct igmphdr *igh; - - if(skb==NULL) - return; - tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL, - skb->mem_len, 0, 1); - if(tmp<0) - { - kfree_skb(skb, FREE_WRITE); - return; - } - igh=(struct igmphdr *)(skb->data+tmp); - skb->len=tmp+sizeof(*igh); - igh->csum=0; - igh->unused=0; - igh->type=type; - igh->group=address; - igh->csum=ip_compute_csum((void *)igh,sizeof(*igh)); - ip_queue_xmit(NULL,dev,skb,1); -} - - -static void igmp_timer_expire(unsigned long data) -{ - struct ip_mc_list *im=(struct ip_mc_list *)data; - igmp_stop_timer(im); - igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT); -} - -static void igmp_init_timer(struct ip_mc_list *im) -{ - im->tm_running=0; - init_timer(&im->timer); - im->timer.data=(unsigned long)im; - im->timer.function=&igmp_timer_expire; -} - - -static void igmp_heard_report(struct device *dev, unsigned long address) -{ - struct ip_mc_list *im; - for(im=dev->ip_mc_list;im!=NULL;im=im->next) - if(im->multiaddr==address) - igmp_stop_timer(im); -} - -static void igmp_heard_query(struct device *dev) -{ - struct ip_mc_list *im; - for(im=dev->ip_mc_list;im!=NULL;im=im->next) - if(!im->tm_running && im->multiaddr!=IGMP_ALL_HOSTS) - igmp_start_timer(im); -} - -/* - * Map a multicast IP onto multicast MAC for type ethernet. - */ - -static void ip_mc_map(unsigned long addr, char *buf) -{ - addr=ntohl(addr); - buf[0]=0x01; - buf[1]=0x00; - buf[2]=0x5e; - buf[5]=addr&0xFF; - addr>>=8; - buf[4]=addr&0xFF; - addr>>=8; - buf[3]=addr&0x7F; -} - -/* - * Add a filter to a device - */ - -void ip_mc_filter_add(struct device *dev, unsigned long addr) -{ - char buf[6]; - if(dev->type!=ARPHRD_ETHER) - return; /* Only do ethernet now */ - ip_mc_map(addr,buf); - dev_mc_add(dev,buf,ETH_ALEN,0); -} - -/* - * Remove a filter from a device - */ - -void ip_mc_filter_del(struct device *dev, unsigned long addr) -{ - char buf[6]; - if(dev->type!=ARPHRD_ETHER) - return; /* Only do ethernet now */ - ip_mc_map(addr,buf); - dev_mc_delete(dev,buf,ETH_ALEN,0); -} - -static void igmp_group_dropped(struct ip_mc_list *im) -{ - del_timer(&im->timer); - igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE); - ip_mc_filter_del(im->interface, im->multiaddr); -/* printk("Left group %lX\n",im->multiaddr);*/ -} - -static void igmp_group_added(struct ip_mc_list *im) -{ - igmp_init_timer(im); - igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT); - ip_mc_filter_add(im->interface, im->multiaddr); -/* printk("Joined group %lX\n",im->multiaddr);*/ -} - -int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, - unsigned long daddr, unsigned short len, unsigned long saddr, int redo, - struct inet_protocol *protocol) -{ - /* This basically follows the spec line by line -- see RFC1112 */ - struct igmphdr *igh=(struct igmphdr *)skb->h.raw; - - if(skb->ip_hdr->ttl!=1 || ip_compute_csum((void *)igh,sizeof(*igh))) - { - kfree_skb(skb, FREE_READ); - return 0; - } - - if(igh->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS) - igmp_heard_query(dev); - if(igh->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==igh->group) - igmp_heard_report(dev,igh->group); - kfree_skb(skb, FREE_READ); - return 0; -} - -/* - * Multicast list managers - */ - - -/* - * A socket has joined a multicast group on device dev. - */ - -static void ip_mc_inc_group(struct device *dev, unsigned long addr) -{ - struct ip_mc_list *i; - for(i=dev->ip_mc_list;i!=NULL;i=i->next) - { - if(i->multiaddr==addr) - { - i->users++; - return; - } - } - i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL); - if(!i) - return; - i->users=1; - i->interface=dev; - i->multiaddr=addr; - i->next=dev->ip_mc_list; - igmp_group_added(i); - dev->ip_mc_list=i; -} - -/* - * A socket has left a multicast group on device dev - */ - -static void ip_mc_dec_group(struct device *dev, unsigned long addr) -{ - struct ip_mc_list **i; - for(i=&(dev->ip_mc_list);(*i)!=NULL;i=&(*i)->next) - { - if((*i)->multiaddr==addr) - { - if(--((*i)->users)) - return; - else - { - struct ip_mc_list *tmp= *i; - igmp_group_dropped(tmp); - *i=(*i)->next; - kfree_s(tmp,sizeof(*tmp)); - } - } - } -} - -/* - * Device going down: Clean up. - */ - -void ip_mc_drop_device(struct device *dev) -{ - struct ip_mc_list *i; - struct ip_mc_list *j; - for(i=dev->ip_mc_list;i!=NULL;i=j) - { - j=i->next; - kfree_s(i,sizeof(*i)); - } - dev->ip_mc_list=NULL; -} - -/* - * Device going up. Make sure it is in all hosts - */ - -void ip_mc_allhost(struct device *dev) -{ - struct ip_mc_list *i; - for(i=dev->ip_mc_list;i!=NULL;i=i->next) - if(i->multiaddr==IGMP_ALL_HOSTS) - return; - i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL); - if(!i) - return; - i->users=1; - i->interface=dev; - i->multiaddr=IGMP_ALL_HOSTS; - i->next=dev->ip_mc_list; - dev->ip_mc_list=i; - ip_mc_filter_add(i->interface, i->multiaddr); - -} - -/* - * Join a socket to a group - */ - -int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr) -{ - int unused= -1; - int i; - if(!MULTICAST(addr)) - return -EINVAL; - if(!(dev->flags&IFF_MULTICAST)) - return -EADDRNOTAVAIL; - if(sk->ip_mc_list==NULL) - { - if((sk->ip_mc_list=(struct ip_mc_socklist *)kmalloc(sizeof(*sk->ip_mc_list), GFP_KERNEL))==NULL) - return -ENOMEM; - memset(sk->ip_mc_list,'\0',sizeof(*sk->ip_mc_list)); - } - for(i=0;iip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev) - return -EADDRINUSE; - if(sk->ip_mc_list->multidev[i]==NULL) - unused=i; - } - - if(unused==-1) - return -ENOBUFS; - sk->ip_mc_list->multiaddr[unused]=addr; - sk->ip_mc_list->multidev[unused]=dev; - ip_mc_inc_group(dev,addr); - return 0; -} - -/* - * Ask a socket to leave a group. - */ - -int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr) -{ - int i; - if(!MULTICAST(addr)) - return -EINVAL; - if(!(dev->flags&IFF_MULTICAST)) - return -EADDRNOTAVAIL; - if(sk->ip_mc_list==NULL) - return -EADDRNOTAVAIL; - - for(i=0;iip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev) - { - sk->ip_mc_list->multidev[i]=NULL; - ip_mc_dec_group(dev,addr); - return 0; - } - } - return -EADDRNOTAVAIL; -} - -/* - * A socket is closing. - */ - -void ip_mc_drop_socket(struct sock *sk) -{ - int i; - - if(sk->ip_mc_list==NULL) - return; - - for(i=0;iip_mc_list->multidev[i]) - { - ip_mc_dec_group(sk->ip_mc_list->multidev[i], sk->ip_mc_list->multiaddr[i]); - sk->ip_mc_list->multidev[i]=NULL; - } - } - kfree_s(sk->ip_mc_list,sizeof(*sk->ip_mc_list)); - sk->ip_mc_list=NULL; -} - -#endif diff --git a/pfinet/linux-inet/ip.c b/pfinet/linux-inet/ip.c deleted file mode 100644 index dd188f54..00000000 --- a/pfinet/linux-inet/ip.c +++ /dev/null @@ -1,2427 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The Internet Protocol (IP) module. - * - * Version: @(#)ip.c 1.0.16b 9/1/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Richard Underwood - * Stefan Becker, - * - * - * Fixes: - * Alan Cox : Commented a couple of minor bits of surplus code - * Alan Cox : Undefining IP_FORWARD doesn't include the code - * (just stops a compiler warning). - * Alan Cox : Frames with >=MAX_ROUTE record routes, strict routes or loose routes - * are junked rather than corrupting things. - * Alan Cox : Frames to bad broadcast subnets are dumped - * We used to process them non broadcast and - * boy could that cause havoc. - * Alan Cox : ip_forward sets the free flag on the - * new frame it queues. Still crap because - * it copies the frame but at least it - * doesn't eat memory too. - * Alan Cox : Generic queue code and memory fixes. - * Fred Van Kempen : IP fragment support (borrowed from NET2E) - * Gerhard Koerting: Forward fragmented frames correctly. - * Gerhard Koerting: Fixes to my fix of the above 8-). - * Gerhard Koerting: IP interface addressing fix. - * Linus Torvalds : More robustness checks - * Alan Cox : Even more checks: Still not as robust as it ought to be - * Alan Cox : Save IP header pointer for later - * Alan Cox : ip option setting - * Alan Cox : Use ip_tos/ip_ttl settings - * Alan Cox : Fragmentation bogosity removed - * (Thanks to Mark.Bush@prg.ox.ac.uk) - * Dmitry Gorodchanin : Send of a raw packet crash fix. - * Alan Cox : Silly ip bug when an overlength - * fragment turns up. Now frees the - * queue. - * Linus Torvalds/ : Memory leakage on fragmentation - * Alan Cox : handling. - * Gerhard Koerting: Forwarding uses IP priority hints - * Teemu Rantanen : Fragment problems. - * Alan Cox : General cleanup, comments and reformat - * Alan Cox : SNMP statistics - * Alan Cox : BSD address rule semantics. Also see - * UDP as there is a nasty checksum issue - * if you do things the wrong way. - * Alan Cox : Always defrag, moved IP_FORWARD to the config.in file - * Alan Cox : IP options adjust sk->priority. - * Pedro Roque : Fix mtu/length error in ip_forward. - * Alan Cox : Avoid ip_chk_addr when possible. - * Richard Underwood : IP multicasting. - * Alan Cox : Cleaned up multicast handlers. - * Alan Cox : RAW sockets demultiplex in the BSD style. - * Gunther Mayer : Fix the SNMP reporting typo - * Alan Cox : Always in group 224.0.0.1 - * Alan Cox : Multicast loopback error for 224.0.0.1 - * Alan Cox : IP_MULTICAST_LOOP option. - * Alan Cox : Use notifiers. - * Bjorn Ekwall : Removed ip_csum (from slhc.c too) - * Bjorn Ekwall : Moved ip_fast_csum to ip.h (inline!) - * Stefan Becker : Send out ICMP HOST REDIRECT - * Alan Cox : Only send ICMP_REDIRECT if src/dest are the same net. - * - * - * To Fix: - * IP option processing is mostly not needed. ip_forward needs to know about routing rules - * and time stamp but that's about all. Use the route mtu field here too - * IP fragmentation wants rewriting cleanly. The RFC815 algorithm is much more efficient - * and could be made very efficient with the addition of some virtual memory hacks to permit - * the allocation of a buffer that can then be 'grown' by twiddling page tables. - * Output fragmentation wants updating along with the buffer management to use a single - * interleaved copy algorithm so that fragmenting has a one copy overhead. Actual packet - * output should probably do its own fragmentation at the UDP/RAW layer. TCP shouldn't cause - * fragmentation anyway. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "snmp.h" -#include "ip.h" -#include "protocol.h" -#include "route.h" -#include "tcp.h" -#include "udp.h" -#include -#include "sock.h" -#include "arp.h" -#include "icmp.h" -#include "raw.h" -#include -#include - -#define CONFIG_IP_DEFRAG - -extern int last_retran; -extern void sort_send(struct sock *sk); - -#define min(a,b) ((a)<(b)?(a):(b)) -#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000)) - -/* - * SNMP management statistics - */ - -#ifdef CONFIG_IP_FORWARD -struct ip_mib ip_statistics={1,64,}; /* Forwarding=Yes, Default TTL=64 */ -#else -struct ip_mib ip_statistics={0,64,}; /* Forwarding=No, Default TTL=64 */ -#endif - -/* - * Handle the issuing of an ioctl() request - * for the ip device. This is scheduled to - * disappear - */ - -int ip_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - switch(cmd) - { - default: - return(-EINVAL); - } -} - - -/* these two routines will do routing. */ - -static void -strict_route(struct iphdr *iph, struct options *opt) -{ -} - - -static void -loose_route(struct iphdr *iph, struct options *opt) -{ -} - - - - -/* This routine will check to see if we have lost a gateway. */ -void -ip_route_check(unsigned long daddr) -{ -} - - -#if 0 -/* this routine puts the options at the end of an ip header. */ -static int -build_options(struct iphdr *iph, struct options *opt) -{ - unsigned char *ptr; - /* currently we don't support any options. */ - ptr = (unsigned char *)(iph+1); - *ptr = 0; - return (4); -} -#endif - - -/* - * Take an skb, and fill in the MAC header. - */ - -static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr) -{ - int mac = 0; - - skb->dev = dev; - skb->arp = 1; - if (dev->hard_header) - { - /* - * Build a hardware header. Source address is our mac, destination unknown - * (rebuild header will sort this out) - */ - mac = dev->hard_header(skb->data, dev, ETH_P_IP, NULL, NULL, len, skb); - if (mac < 0) - { - mac = -mac; - skb->arp = 0; - skb->raddr = daddr; /* next routing address */ - } - } - return mac; -} - -int ip_id_count = 0; - -/* - * This routine builds the appropriate hardware/IP headers for - * the routine. It assumes that if *dev != NULL then the - * protocol knows what it's doing, otherwise it uses the - * routing/ARP tables to select a device struct. - */ -int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, - struct device **dev, int type, struct options *opt, int len, int tos, int ttl) -{ - static struct options optmem; - struct iphdr *iph; - struct rtable *rt; - unsigned char *buff; - unsigned long raddr; - int tmp; - unsigned long src; - - buff = skb->data; - - /* - * See if we need to look up the device. - */ - -#ifdef CONFIG_INET_MULTICAST - if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name) - *dev=dev_get(skb->sk->ip_mc_name); -#endif - if (*dev == NULL) - { - if(skb->localroute) - rt = ip_rt_local(daddr, &optmem, &src); - else - rt = ip_rt_route(daddr, &optmem, &src); - if (rt == NULL) - { - ip_statistics.IpOutNoRoutes++; - return(-ENETUNREACH); - } - - *dev = rt->rt_dev; - /* - * If the frame is from us and going off machine it MUST MUST MUST - * have the output device ip address and never the loopback - */ - if (LOOPBACK(saddr) && !LOOPBACK(daddr)) - saddr = src;/*rt->rt_dev->pa_addr;*/ - raddr = rt->rt_gateway; - - opt = &optmem; - } - else - { - /* - * We still need the address of the first hop. - */ - if(skb->localroute) - rt = ip_rt_local(daddr, &optmem, &src); - else - rt = ip_rt_route(daddr, &optmem, &src); - /* - * If the frame is from us and going off machine it MUST MUST MUST - * have the output device ip address and never the loopback - */ - if (LOOPBACK(saddr) && !LOOPBACK(daddr)) - saddr = src;/*rt->rt_dev->pa_addr;*/ - - raddr = (rt == NULL) ? 0 : rt->rt_gateway; - } - - /* - * No source addr so make it our addr - */ - if (saddr == 0) - saddr = src; - - /* - * No gateway so aim at the real destination - */ - if (raddr == 0) - raddr = daddr; - - /* - * Now build the MAC header. - */ - - tmp = ip_send(skb, raddr, len, *dev, saddr); - buff += tmp; - len -= tmp; - - /* - * Book keeping - */ - - skb->dev = *dev; - skb->saddr = saddr; - if (skb->sk) - skb->sk->saddr = saddr; - - /* - * Now build the IP header. - */ - - /* - * If we are using IPPROTO_RAW, then we don't need an IP header, since - * one is being supplied to us by the user - */ - - if(type == IPPROTO_RAW) - return (tmp); - - iph = (struct iphdr *)buff; - iph->version = 4; - iph->tos = tos; - iph->frag_off = 0; - iph->ttl = ttl; - iph->daddr = daddr; - iph->saddr = saddr; - iph->protocol = type; - iph->ihl = 5; - skb->ip_hdr = iph; - - /* Setup the IP options. */ -#ifdef Not_Yet_Avail - build_options(iph, opt); -#endif - - return(20 + tmp); /* IP header plus MAC header size */ -} - - -static int -do_options(struct iphdr *iph, struct options *opt) -{ - unsigned char *buff; - int done = 0; - int i, len = sizeof(struct iphdr); - - /* Zero out the options. */ - opt->record_route.route_size = 0; - opt->loose_route.route_size = 0; - opt->strict_route.route_size = 0; - opt->tstamp.ptr = 0; - opt->security = 0; - opt->compartment = 0; - opt->handling = 0; - opt->stream = 0; - opt->tcc = 0; - return(0); - - /* Advance the pointer to start at the options. */ - buff = (unsigned char *)(iph + 1); - - /* Now start the processing. */ - while (!done && len < iph->ihl*4) switch(*buff) { - case IPOPT_END: - done = 1; - break; - case IPOPT_NOOP: - buff++; - len++; - break; - case IPOPT_SEC: - buff++; - if (*buff != 11) return(1); - buff++; - opt->security = ntohs(*(unsigned short *)buff); - buff += 2; - opt->compartment = ntohs(*(unsigned short *)buff); - buff += 2; - opt->handling = ntohs(*(unsigned short *)buff); - buff += 2; - opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1)); - buff += 3; - len += 11; - break; - case IPOPT_LSRR: - buff++; - if ((*buff - 3)% 4 != 0) return(1); - len += *buff; - opt->loose_route.route_size = (*buff -3)/4; - buff++; - if (*buff % 4 != 0) return(1); - opt->loose_route.pointer = *buff/4 - 1; - buff++; - buff++; - for (i = 0; i < opt->loose_route.route_size; i++) { - if(i>=MAX_ROUTE) - return(1); - opt->loose_route.route[i] = *(unsigned long *)buff; - buff += 4; - } - break; - case IPOPT_SSRR: - buff++; - if ((*buff - 3)% 4 != 0) return(1); - len += *buff; - opt->strict_route.route_size = (*buff -3)/4; - buff++; - if (*buff % 4 != 0) return(1); - opt->strict_route.pointer = *buff/4 - 1; - buff++; - buff++; - for (i = 0; i < opt->strict_route.route_size; i++) { - if(i>=MAX_ROUTE) - return(1); - opt->strict_route.route[i] = *(unsigned long *)buff; - buff += 4; - } - break; - case IPOPT_RR: - buff++; - if ((*buff - 3)% 4 != 0) return(1); - len += *buff; - opt->record_route.route_size = (*buff -3)/4; - buff++; - if (*buff % 4 != 0) return(1); - opt->record_route.pointer = *buff/4 - 1; - buff++; - buff++; - for (i = 0; i < opt->record_route.route_size; i++) { - if(i>=MAX_ROUTE) - return 1; - opt->record_route.route[i] = *(unsigned long *)buff; - buff += 4; - } - break; - case IPOPT_SID: - len += 4; - buff +=2; - opt->stream = *(unsigned short *)buff; - buff += 2; - break; - case IPOPT_TIMESTAMP: - buff++; - len += *buff; - if (*buff % 4 != 0) return(1); - opt->tstamp.len = *buff / 4 - 1; - buff++; - if ((*buff - 1) % 4 != 0) return(1); - opt->tstamp.ptr = (*buff-1)/4; - buff++; - opt->tstamp.x.full_char = *buff; - buff++; - for (i = 0; i < opt->tstamp.len; i++) { - opt->tstamp.data[i] = *(unsigned long *)buff; - buff += 4; - } - break; - default: - return(1); - } - - if (opt->record_route.route_size == 0) { - if (opt->strict_route.route_size != 0) { - memcpy(&(opt->record_route), &(opt->strict_route), - sizeof(opt->record_route)); - } else if (opt->loose_route.route_size != 0) { - memcpy(&(opt->record_route), &(opt->loose_route), - sizeof(opt->record_route)); - } - } - - if (opt->strict_route.route_size != 0 && - opt->strict_route.route_size != opt->strict_route.pointer) { - strict_route(iph, opt); - return(0); - } - - if (opt->loose_route.route_size != 0 && - opt->loose_route.route_size != opt->loose_route.pointer) { - loose_route(iph, opt); - return(0); - } - - return(0); -} - -/* - * This routine does all the checksum computations that don't - * require anything special (like copying or special headers). - */ - -unsigned short ip_compute_csum(unsigned char * buff, int len) -{ - unsigned long sum = 0; - - /* Do the first multiple of 4 bytes and convert to 16 bits. */ - if (len > 3) - { - __asm__("clc\n" - "1:\t" - "lodsl\n\t" - "adcl %%eax, %%ebx\n\t" - "loop 1b\n\t" - "adcl $0, %%ebx\n\t" - "movl %%ebx, %%eax\n\t" - "shrl $16, %%eax\n\t" - "addw %%ax, %%bx\n\t" - "adcw $0, %%bx" - : "=b" (sum) , "=S" (buff) - : "0" (sum), "c" (len >> 2) ,"1" (buff) - : "ax", "cx", "si", "bx" ); - } - if (len & 2) - { - __asm__("lodsw\n\t" - "addw %%ax, %%bx\n\t" - "adcw $0, %%bx" - : "=b" (sum), "=S" (buff) - : "0" (sum), "1" (buff) - : "bx", "ax", "si"); - } - if (len & 1) - { - __asm__("lodsb\n\t" - "movb $0, %%ah\n\t" - "addw %%ax, %%bx\n\t" - "adcw $0, %%bx" - : "=b" (sum), "=S" (buff) - : "0" (sum), "1" (buff) - : "bx", "ax", "si"); - } - sum =~sum; - return(sum & 0xffff); -} - -/* - * Generate a checksum for an outgoing IP datagram. - */ - -void ip_send_check(struct iphdr *iph) -{ - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); -} - -/************************ Fragment Handlers From NET2E **********************************/ - - -/* - * This fragment handler is a bit of a heap. On the other hand it works quite - * happily and handles things quite well. - */ - -static struct ipq *ipqueue = NULL; /* IP fragment queue */ - -/* - * Create a new fragment entry. - */ - -static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr) -{ - struct ipfrag *fp; - - fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC); - if (fp == NULL) - { - printk("IP: frag_create: no memory left !\n"); - return(NULL); - } - memset(fp, 0, sizeof(struct ipfrag)); - - /* Fill in the structure. */ - fp->offset = offset; - fp->end = end; - fp->len = end - offset; - fp->skb = skb; - fp->ptr = ptr; - - return(fp); -} - - -/* - * Find the correct entry in the "incomplete datagrams" queue for - * this IP datagram, and return the queue entry address if found. - */ - -static struct ipq *ip_find(struct iphdr *iph) -{ - struct ipq *qp; - struct ipq *qplast; - - cli(); - qplast = NULL; - for(qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next) - { - if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr && - iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol) - { - del_timer(&qp->timer); /* So it doesn't vanish on us. The timer will be reset anyway */ - sti(); - return(qp); - } - } - sti(); - return(NULL); -} - - -/* - * Remove an entry from the "incomplete datagrams" queue, either - * because we completed, reassembled and processed it, or because - * it timed out. - */ - -static void ip_free(struct ipq *qp) -{ - struct ipfrag *fp; - struct ipfrag *xp; - - /* - * Stop the timer for this entry. - */ - - del_timer(&qp->timer); - - /* Remove this entry from the "incomplete datagrams" queue. */ - cli(); - if (qp->prev == NULL) - { - ipqueue = qp->next; - if (ipqueue != NULL) - ipqueue->prev = NULL; - } - else - { - qp->prev->next = qp->next; - if (qp->next != NULL) - qp->next->prev = qp->prev; - } - - /* Release all fragment data. */ - - fp = qp->fragments; - while (fp != NULL) - { - xp = fp->next; - IS_SKB(fp->skb); - kfree_skb(fp->skb,FREE_READ); - kfree_s(fp, sizeof(struct ipfrag)); - fp = xp; - } - - /* Release the MAC header. */ - kfree_s(qp->mac, qp->maclen); - - /* Release the IP header. */ - kfree_s(qp->iph, qp->ihlen + 8); - - /* Finally, release the queue descriptor itself. */ - kfree_s(qp, sizeof(struct ipq)); - sti(); -} - - -/* - * Oops- a fragment queue timed out. Kill it and send an ICMP reply. - */ - -static void ip_expire(unsigned long arg) -{ - struct ipq *qp; - - qp = (struct ipq *)arg; - - /* - * Send an ICMP "Fragment Reassembly Timeout" message. - */ - - ip_statistics.IpReasmTimeout++; - ip_statistics.IpReasmFails++; - /* This if is always true... shrug */ - if(qp->fragments!=NULL) - icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, - ICMP_EXC_FRAGTIME, 0, qp->dev); - - /* - * Nuke the fragment queue. - */ - ip_free(qp); -} - - -/* - * Add an entry to the 'ipq' queue for a newly received IP datagram. - * We will (hopefully :-) receive all other fragments of this datagram - * in time, so we just create a queue for this datagram, in which we - * will insert the received fragments at their respective positions. - */ - -static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev) -{ - struct ipq *qp; - int maclen; - int ihlen; - - qp = (struct ipq *) kmalloc(sizeof(struct ipq), GFP_ATOMIC); - if (qp == NULL) - { - printk("IP: create: no memory left !\n"); - return(NULL); - skb->dev = qp->dev; - } - memset(qp, 0, sizeof(struct ipq)); - - /* - * Allocate memory for the MAC header. - * - * FIXME: We have a maximum MAC address size limit and define - * elsewhere. We should use it here and avoid the 3 kmalloc() calls - */ - - maclen = ((unsigned long) iph) - ((unsigned long) skb->data); - qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC); - if (qp->mac == NULL) - { - printk("IP: create: no memory left !\n"); - kfree_s(qp, sizeof(struct ipq)); - return(NULL); - } - - /* - * Allocate memory for the IP header (plus 8 octets for ICMP). - */ - - ihlen = (iph->ihl * sizeof(unsigned long)); - qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC); - if (qp->iph == NULL) - { - printk("IP: create: no memory left !\n"); - kfree_s(qp->mac, maclen); - kfree_s(qp, sizeof(struct ipq)); - return(NULL); - } - - /* Fill in the structure. */ - memcpy(qp->mac, skb->data, maclen); - memcpy(qp->iph, iph, ihlen + 8); - qp->len = 0; - qp->ihlen = ihlen; - qp->maclen = maclen; - qp->fragments = NULL; - qp->dev = dev; - - /* Start a timer for this entry. */ - qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ - qp->timer.data = (unsigned long) qp; /* pointer to queue */ - qp->timer.function = ip_expire; /* expire function */ - add_timer(&qp->timer); - - /* Add this entry to the queue. */ - qp->prev = NULL; - cli(); - qp->next = ipqueue; - if (qp->next != NULL) - qp->next->prev = qp; - ipqueue = qp; - sti(); - return(qp); -} - - -/* - * See if a fragment queue is complete. - */ - -static int ip_done(struct ipq *qp) -{ - struct ipfrag *fp; - int offset; - - /* Only possible if we received the final fragment. */ - if (qp->len == 0) - return(0); - - /* Check all fragment offsets to see if they connect. */ - fp = qp->fragments; - offset = 0; - while (fp != NULL) - { - if (fp->offset > offset) - return(0); /* fragment(s) missing */ - offset = fp->end; - fp = fp->next; - } - - /* All fragments are present. */ - return(1); -} - - -/* - * Build a new IP datagram from all its fragments. - * - * FIXME: We copy here because we lack an effective way of handling lists - * of bits on input. Until the new skb data handling is in I'm not going - * to touch this with a bargepole. This also causes a 4Kish limit on - * packet sizes. - */ - -static struct sk_buff *ip_glue(struct ipq *qp) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct ipfrag *fp; - unsigned char *ptr; - int count, len; - - /* - * Allocate a new buffer for the datagram. - */ - - len = qp->maclen + qp->ihlen + qp->len; - - if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL) - { - ip_statistics.IpReasmFails++; - printk("IP: queue_glue: no memory for gluing queue 0x%X\n", (int) qp); - ip_free(qp); - return(NULL); - } - - /* Fill in the basic details. */ - skb->len = (len - qp->maclen); - skb->h.raw = skb->data; - skb->free = 1; - - /* Copy the original MAC and IP headers into the new buffer. */ - ptr = (unsigned char *) skb->h.raw; - memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen); - ptr += qp->maclen; - memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen); - ptr += qp->ihlen; - skb->h.raw += qp->maclen; - - count = 0; - - /* Copy the data portions of all fragments into the new buffer. */ - fp = qp->fragments; - while(fp != NULL) - { - if(count+fp->len > skb->len) - { - printk("Invalid fragment list: Fragment over size.\n"); - ip_free(qp); - kfree_skb(skb,FREE_WRITE); - ip_statistics.IpReasmFails++; - return NULL; - } - memcpy((ptr + fp->offset), fp->ptr, fp->len); - count += fp->len; - fp = fp->next; - } - - /* We glued together all fragments, so remove the queue entry. */ - ip_free(qp); - - /* Done with all fragments. Fixup the new IP header. */ - iph = skb->h.iph; - iph->frag_off = 0; - iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count); - skb->ip_hdr = iph; - - ip_statistics.IpReasmOKs++; - return(skb); -} - - -/* - * Process an incoming IP datagram fragment. - */ - -static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev) -{ - struct ipfrag *prev, *next; - struct ipfrag *tfp; - struct ipq *qp; - struct sk_buff *skb2; - unsigned char *ptr; - int flags, offset; - int i, ihl, end; - - ip_statistics.IpReasmReqds++; - - /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */ - qp = ip_find(iph); - - /* Is this a non-fragmented datagram? */ - offset = ntohs(iph->frag_off); - flags = offset & ~IP_OFFSET; - offset &= IP_OFFSET; - if (((flags & IP_MF) == 0) && (offset == 0)) - { - if (qp != NULL) - ip_free(qp); /* Huh? How could this exist?? */ - return(skb); - } - - offset <<= 3; /* offset is in 8-byte chunks */ - - /* - * If the queue already existed, keep restarting its timer as long - * as we still are receiving fragments. Otherwise, create a fresh - * queue entry. - */ - - if (qp != NULL) - { - del_timer(&qp->timer); - qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ - qp->timer.data = (unsigned long) qp; /* pointer to queue */ - qp->timer.function = ip_expire; /* expire function */ - add_timer(&qp->timer); - } - else - { - /* - * If we failed to create it, then discard the frame - */ - if ((qp = ip_create(skb, iph, dev)) == NULL) - { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - ip_statistics.IpReasmFails++; - return NULL; - } - } - - /* - * Determine the position of this fragment. - */ - - ihl = (iph->ihl * sizeof(unsigned long)); - end = offset + ntohs(iph->tot_len) - ihl; - - /* - * Point into the IP datagram 'data' part. - */ - - ptr = skb->data + dev->hard_header_len + ihl; - - /* - * Is this the final fragment? - */ - - if ((flags & IP_MF) == 0) - qp->len = end; - - /* - * Find out which fragments are in front and at the back of us - * in the chain of fragments so far. We must know where to put - * this fragment, right? - */ - - prev = NULL; - for(next = qp->fragments; next != NULL; next = next->next) - { - if (next->offset > offset) - break; /* bingo! */ - prev = next; - } - - /* - * We found where to put this one. - * Check for overlap with preceding fragment, and, if needed, - * align things so that any overlaps are eliminated. - */ - if (prev != NULL && offset < prev->end) - { - i = prev->end - offset; - offset += i; /* ptr into datagram */ - ptr += i; /* ptr into fragment data */ - } - - /* - * Look for overlap with succeeding segments. - * If we can merge fragments, do it. - */ - - for(; next != NULL; next = tfp) - { - tfp = next->next; - if (next->offset >= end) - break; /* no overlaps at all */ - - i = end - next->offset; /* overlap is 'i' bytes */ - next->len -= i; /* so reduce size of */ - next->offset += i; /* next fragment */ - next->ptr += i; - - /* - * If we get a frag size of <= 0, remove it and the packet - * that it goes with. - */ - if (next->len <= 0) - { - if (next->prev != NULL) - next->prev->next = next->next; - else - qp->fragments = next->next; - - if (tfp->next != NULL) - next->next->prev = next->prev; - - kfree_skb(next->skb,FREE_READ); - kfree_s(next, sizeof(struct ipfrag)); - } - } - - /* - * Insert this fragment in the chain of fragments. - */ - - tfp = NULL; - tfp = ip_frag_create(offset, end, skb, ptr); - - /* - * No memory to save the fragment - so throw the lot - */ - - if (!tfp) - { - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return NULL; - } - tfp->prev = prev; - tfp->next = next; - if (prev != NULL) - prev->next = tfp; - else - qp->fragments = tfp; - - if (next != NULL) - next->prev = tfp; - - /* - * OK, so we inserted this new fragment into the chain. - * Check if we now have a full IP datagram which we can - * bump up to the IP layer... - */ - - if (ip_done(qp)) - { - skb2 = ip_glue(qp); /* glue together the fragments */ - return(skb2); - } - return(NULL); -} - - -/* - * This IP datagram is too large to be sent in one piece. Break it up into - * smaller pieces (each of size equal to the MAC header plus IP header plus - * a block of the data of the original IP data part) that will yet fit in a - * single device frame, and queue such a frame for sending by calling the - * ip_queue_xmit(). Note that this is recursion, and bad things will happen - * if this function causes a loop... - * - * Yes this is inefficient, feel free to submit a quicker one. - * - * **Protocol Violation** - * We copy all the options to each fragment. !FIXME! - */ -void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag) -{ - struct iphdr *iph; - unsigned char *raw; - unsigned char *ptr; - struct sk_buff *skb2; - int left, mtu, hlen, len; - int offset; - unsigned long flags; - - /* - * Point into the IP datagram header. - */ - - raw = skb->data; - iph = (struct iphdr *) (raw + dev->hard_header_len); - - skb->ip_hdr = iph; - - /* - * Setup starting values. - */ - - hlen = (iph->ihl * sizeof(unsigned long)); - left = ntohs(iph->tot_len) - hlen; /* Space per frame */ - hlen += dev->hard_header_len; /* Total header size */ - mtu = (dev->mtu - hlen); /* Size of data space */ - ptr = (raw + hlen); /* Where to start from */ - - /* - * Check for any "DF" flag. [DF means do not fragment] - */ - - if (ntohs(iph->frag_off) & IP_DF) - { - /* - * Reply giving the MTU of the failed hop. - */ - ip_statistics.IpFragFails++; - icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev->mtu, dev); - return; - } - - /* - * The protocol doesn't seem to say what to do in the case that the - * frame + options doesn't fit the mtu. As it used to fall down dead - * in this case we were fortunate it didn't happen - */ - - if(mtu<8) - { - /* It's wrong but it's better than nothing */ - icmp_send(skb,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,dev->mtu, dev); - ip_statistics.IpFragFails++; - return; - } - - /* - * Fragment the datagram. - */ - - /* - * The initial offset is 0 for a complete frame. When - * fragmenting fragments it's wherever this one starts. - */ - - if (is_frag & 2) - offset = (ntohs(iph->frag_off) & 0x1fff) << 3; - else - offset = 0; - - - /* - * Keep copying data until we run out. - */ - - while(left > 0) - { - len = left; - /* IF: it doesn't fit, use 'mtu' - the data space left */ - if (len > mtu) - len = mtu; - /* IF: we are not sending upto and including the packet end - then align the next start on an eight byte boundary */ - if (len < left) - { - len/=8; - len*=8; - } - /* - * Allocate buffer. - */ - - if ((skb2 = alloc_skb(len + hlen,GFP_ATOMIC)) == NULL) - { - printk("IP: frag: no memory for new fragment!\n"); - ip_statistics.IpFragFails++; - return; - } - - /* - * Set up data on packet - */ - - skb2->arp = skb->arp; - if(skb->free==0) - printk("IP fragmenter: BUG free!=1 in fragmenter\n"); - skb2->free = 1; - skb2->len = len + hlen; - skb2->h.raw=(char *) skb2->data; - /* - * Charge the memory for the fragment to any owner - * it might possess - */ - - save_flags(flags); - if (sk) - { - cli(); - sk->wmem_alloc += skb2->mem_len; - skb2->sk=sk; - } - restore_flags(flags); - skb2->raddr = skb->raddr; /* For rebuild_header - must be here */ - - /* - * Copy the packet header into the new buffer. - */ - - memcpy(skb2->h.raw, raw, hlen); - - /* - * Copy a block of the IP datagram. - */ - memcpy(skb2->h.raw + hlen, ptr, len); - left -= len; - - skb2->h.raw+=dev->hard_header_len; - - /* - * Fill in the new header fields. - */ - iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/); - iph->frag_off = htons((offset >> 3)); - /* - * Added AC : If we are fragmenting a fragment thats not the - * last fragment then keep MF on each bit - */ - if (left > 0 || (is_frag & 1)) - iph->frag_off |= htons(IP_MF); - ptr += len; - offset += len; - - /* - * Put this fragment into the sending queue. - */ - - ip_statistics.IpFragCreates++; - - ip_queue_xmit(sk, dev, skb2, 2); - } - ip_statistics.IpFragOKs++; -} - - - -#ifdef CONFIG_IP_FORWARD - -/* - * Forward an IP datagram to its next destination. - */ - -static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) -{ - struct device *dev2; /* Output device */ - struct iphdr *iph; /* Our header */ - struct sk_buff *skb2; /* Output packet */ - struct rtable *rt; /* Route we use */ - unsigned char *ptr; /* Data pointer */ - unsigned long raddr; /* Router IP address */ - - /* - * See if we are allowed to forward this. - */ - -#ifdef CONFIG_IP_FIREWALL - int err; - - if((err=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0))!=1) - { - if(err==-1) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); - return; - } -#endif - /* - * According to the RFC, we must first decrease the TTL field. If - * that reaches zero, we must reply an ICMP control message telling - * that the packet's lifetime expired. - * - * Exception: - * We may not generate an ICMP for an ICMP. icmp_send does the - * enforcement of this so we can forget it here. It is however - * sometimes VERY important. - */ - - iph = skb->h.iph; - iph->ttl--; - if (iph->ttl <= 0) - { - /* Tell the sender its packet died... */ - icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev); - return; - } - - /* - * Re-compute the IP header checksum. - * This is inefficient. We know what has happened to the header - * and could thus adjust the checksum as Phil Karn does in KA9Q - */ - - ip_send_check(iph); - - /* - * OK, the packet is still valid. Fetch its destination address, - * and give it to the IP sender for further processing. - */ - - rt = ip_rt_route(iph->daddr, NULL, NULL); - if (rt == NULL) - { - /* - * Tell the sender its packet cannot be delivered. Again - * ICMP is screened later. - */ - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev); - return; - } - - - /* - * Gosh. Not only is the packet valid; we even know how to - * forward it onto its final destination. Can we say this - * is being plain lucky? - * If the router told us that there is no GW, use the dest. - * IP address itself- we seem to be connected directly... - */ - - raddr = rt->rt_gateway; - - if (raddr != 0) - { - /* - * There is a gateway so find the correct route for it. - * Gateways cannot in turn be gatewayed. - */ - rt = ip_rt_route(raddr, NULL, NULL); - if (rt == NULL) - { - /* - * Tell the sender its packet cannot be delivered... - */ - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); - return; - } - if (rt->rt_gateway != 0) - raddr = rt->rt_gateway; - } - else - raddr = iph->daddr; - - /* - * Having picked a route we can now send the frame out. - */ - - dev2 = rt->rt_dev; - - /* - * In IP you never have to forward a frame on the interface that it - * arrived upon. We now generate an ICMP HOST REDIRECT giving the route - * we calculated. - */ -#ifdef CONFIG_IP_NO_ICMP_REDIRECT - if (dev == dev2) - return; -#else - if (dev == dev2 && (iph->saddr&dev->pa_mask) == (iph->daddr & dev->pa_mask)) - icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev); -#endif - - /* - * We now allocate a new buffer, and copy the datagram into it. - * If the indicated interface is up and running, kick it. - */ - - if (dev2->flags & IFF_UP) - { - - /* - * Current design decrees we copy the packet. For identical header - * lengths we could avoid it. The new skb code will let us push - * data so the problem goes away then. - */ - - skb2 = alloc_skb(dev2->hard_header_len + skb->len, GFP_ATOMIC); - /* - * This is rare and since IP is tolerant of network failures - * quite harmless. - */ - if (skb2 == NULL) - { - printk("\nIP: No memory available for IP forward\n"); - return; - } - ptr = skb2->data; - skb2->free = 1; - skb2->len = skb->len + dev2->hard_header_len; - skb2->h.raw = ptr; - - /* - * Copy the packet data into the new buffer. - */ - memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len); - - /* Now build the MAC header. */ - (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr); - - ip_statistics.IpForwDatagrams++; - - /* - * See if it needs fragmenting. Note in ip_rcv we tagged - * the fragment type. This must be right so that - * the fragmenter does the right thing. - */ - - if(skb2->len > dev2->mtu + dev2->hard_header_len) - { - ip_fragment(NULL,skb2,dev2, is_frag); - kfree_skb(skb2,FREE_WRITE); - } - else - { -#ifdef CONFIG_IP_ACCT - /* - * Count mapping we shortcut - */ - - ip_acct_cnt(iph,dev,ip_acct_chain); -#endif - - /* - * Map service types to priority. We lie about - * throughput being low priority, but it's a good - * choice to help improve general usage. - */ - if(iph->tos & IPTOS_LOWDELAY) - dev_queue_xmit(skb2, dev2, SOPRI_INTERACTIVE); - else if(iph->tos & IPTOS_THROUGHPUT) - dev_queue_xmit(skb2, dev2, SOPRI_BACKGROUND); - else - dev_queue_xmit(skb2, dev2, SOPRI_NORMAL); - } - } -} - - -#endif - -/* - * This function receives all incoming IP datagrams. - */ - -int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ - struct iphdr *iph = skb->h.iph; - struct sock *raw_sk=NULL; - unsigned char hash; - unsigned char flag = 0; - unsigned char opts_p = 0; /* Set iff the packet has options. */ - struct inet_protocol *ipprot; - static struct options opt; /* since we don't use these yet, and they - take up stack space. */ - int brd=IS_MYADDR; - int is_frag=0; -#ifdef CONFIG_IP_FIREWALL - int err; -#endif - - ip_statistics.IpInReceives++; - - /* - * Tag the ip header of this packet so we can find it - */ - - skb->ip_hdr = iph; - - /* - * Is the datagram acceptable? - * - * 1. Length at least the size of an ip header - * 2. Version of 4 - * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] - * (4. We ought to check for IP multicast addresses and undefined types.. does this matter ?) - */ - - if (skb->lenihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) - { - ip_statistics.IpInHdrErrors++; - kfree_skb(skb, FREE_WRITE); - return(0); - } - - /* - * See if the firewall wants to dispose of the packet. - */ - -#ifdef CONFIG_IP_FIREWALL - - if ((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy, 0))!=1) - { - if(err==-1) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev); - kfree_skb(skb, FREE_WRITE); - return 0; - } - -#endif - - /* - * Our transport medium may have padded the buffer out. Now we know it - * is IP we can trim to the true length of the frame. - */ - - skb->len=ntohs(iph->tot_len); - - /* - * Next analyse the packet for options. Studies show under one packet in - * a thousand have options.... - */ - - if (iph->ihl != 5) - { /* Fast path for the typical optionless IP packet. */ - memset((char *) &opt, 0, sizeof(opt)); - if (do_options(iph, &opt) != 0) - return 0; - opts_p = 1; - } - - /* - * Remember if the frame is fragmented. - */ - - if(iph->frag_off) - { - if (iph->frag_off & 0x0020) - is_frag|=1; - /* - * Last fragment ? - */ - - if (ntohs(iph->frag_off) & 0x1fff) - is_frag|=2; - } - - /* - * Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. - * - * This is inefficient. While finding out if it is for us we could also compute - * the routing table entry. This is where the great unified cache theory comes - * in as and when someone implements it - * - * For most hosts over 99% of packets match the first conditional - * and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at - * function entry. - */ - - if ( iph->daddr != skb->dev->pa_addr && (brd = ip_chk_addr(iph->daddr)) == 0) - { - /* - * Don't forward multicast or broadcast frames. - */ - - if(skb->pkt_type!=PACKET_HOST || brd==IS_BROADCAST) - { - kfree_skb(skb,FREE_WRITE); - return 0; - } - - /* - * The packet is for another target. Forward the frame - */ - -#ifdef CONFIG_IP_FORWARD - ip_forward(skb, dev, is_frag); -#else -/* printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", - iph->saddr,iph->daddr);*/ - ip_statistics.IpInAddrErrors++; -#endif - /* - * The forwarder is inefficient and copies the packet. We - * free the original now. - */ - - kfree_skb(skb, FREE_WRITE); - return(0); - } - -#ifdef CONFIG_IP_MULTICAST - - if(brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK)) - { - /* - * Check it is for one of our groups - */ - struct ip_mc_list *ip_mc=dev->ip_mc_list; - do - { - if(ip_mc==NULL) - { - kfree_skb(skb, FREE_WRITE); - return 0; - } - if(ip_mc->multiaddr==iph->daddr) - break; - ip_mc=ip_mc->next; - } - while(1); - } -#endif - /* - * Account for the packet - */ - -#ifdef CONFIG_IP_ACCT - ip_acct_cnt(iph,dev, ip_acct_chain); -#endif - - /* - * Reassemble IP fragments. - */ - - if(is_frag) - { - /* Defragment. Obtain the complete packet if there is one */ - skb=ip_defrag(iph,skb,dev); - if(skb==NULL) - return 0; - skb->dev = dev; - iph=skb->h.iph; - } - - - - /* - * Point into the IP datagram, just past the header. - */ - - skb->ip_hdr = iph; - skb->h.raw += iph->ihl*4; - - /* - * Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies. - */ - - hash = iph->protocol & (SOCK_ARRAY_SIZE-1); - - /* If there maybe a raw socket we must check - if not we don't care less */ - if((raw_sk=raw_prot.sock_array[hash])!=NULL) - { - struct sock *sknext=NULL; - struct sk_buff *skb1; - raw_sk=get_sock_raw(raw_sk, hash, iph->saddr, iph->daddr); - if(raw_sk) /* Any raw sockets */ - { - do - { - /* Find the next */ - sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr); - if(sknext) - skb1=skb_clone(skb, GFP_ATOMIC); - else - break; /* One pending raw socket left */ - if(skb1) - raw_rcv(raw_sk, skb1, dev, iph->saddr,iph->daddr); - raw_sk=sknext; - } - while(raw_sk!=NULL); - /* Here either raw_sk is the last raw socket, or NULL if none */ - /* We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy */ - } - } - - /* - * skb->h.raw now points at the protocol beyond the IP header. - */ - - hash = iph->protocol & (MAX_INET_PROTOS -1); - for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next) - { - struct sk_buff *skb2; - - if (ipprot->protocol != iph->protocol) - continue; - /* - * See if we need to make a copy of it. This will - * only be set if more than one protocol wants it. - * and then not for the last one. If there is a pending - * raw delivery wait for that - */ - if (ipprot->copy || raw_sk) - { - skb2 = skb_clone(skb, GFP_ATOMIC); - if(skb2==NULL) - continue; - } - else - { - skb2 = skb; - } - flag = 1; - - /* - * Pass on the datagram to each protocol that wants it, - * based on the datagram protocol. We should really - * check the protocol handler's return values here... - */ - ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr, - (ntohs(iph->tot_len) - (iph->ihl * 4)), - iph->saddr, 0, ipprot); - - } - - /* - * All protocols checked. - * If this packet was a broadcast, we may *not* reply to it, since that - * causes (proven, grin) ARP storms and a leakage of memory (i.e. all - * ICMP reply messages get queued up for transmission...) - */ - - if(raw_sk!=NULL) /* Shift to last raw user */ - raw_rcv(raw_sk, skb, dev, iph->saddr, iph->daddr); - else if (!flag) /* Free and report errors */ - { - if (brd != IS_BROADCAST && brd!=IS_MULTICAST) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0, dev); - kfree_skb(skb, FREE_WRITE); - } - - return(0); -} - -/* - * Loop a packet back to the sender. - */ - -static void ip_loopback(struct device *old_dev, struct sk_buff *skb) -{ - extern struct device loopback_dev; - struct device *dev=&loopback_dev; - int len=skb->len-old_dev->hard_header_len; - struct sk_buff *newskb=alloc_skb(len+dev->hard_header_len, GFP_ATOMIC); - - if(newskb==NULL) - return; - - newskb->link3=NULL; - newskb->sk=NULL; - newskb->dev=dev; - newskb->saddr=skb->saddr; - newskb->daddr=skb->daddr; - newskb->raddr=skb->raddr; - newskb->free=1; - newskb->lock=0; - newskb->users=0; - newskb->pkt_type=skb->pkt_type; - newskb->len=len+dev->hard_header_len; - - - newskb->ip_hdr=(struct iphdr *)(newskb->data+ip_send(newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr)); - memcpy(newskb->ip_hdr,skb->ip_hdr,len); - - /* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */ - - /*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/ - ip_queue_xmit(NULL, dev, newskb, 1); -} - - -/* - * Queues a packet to be sent, and starts the transmitter - * if necessary. if free = 1 then we free the block after - * transmit, otherwise we don't. If free==2 we not only - * free the block but also don't assign a new ip seq number. - * This routine also needs to put in the total length, - * and compute the checksum - */ - -void ip_queue_xmit(struct sock *sk, struct device *dev, - struct sk_buff *skb, int free) -{ - struct iphdr *iph; - unsigned char *ptr; - - /* Sanity check */ - if (dev == NULL) - { - printk("IP: ip_queue_xmit dev = NULL\n"); - return; - } - - IS_SKB(skb); - - /* - * Do some book-keeping in the packet for later - */ - - - skb->dev = dev; - skb->when = jiffies; - - /* - * Find the IP header and set the length. This is bad - * but once we get the skb data handling code in the - * hardware will push its header sensibly and we will - * set skb->ip_hdr to avoid this mess and the fixed - * header length problem - */ - - ptr = skb->data; - ptr += dev->hard_header_len; - iph = (struct iphdr *)ptr; - skb->ip_hdr = iph; - iph->tot_len = ntohs(skb->len-dev->hard_header_len); - -#ifdef CONFIG_IP_FIREWALL - if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) != 1) - /* just don't send this packet */ - return; -#endif - - /* - * No reassigning numbers to fragments... - */ - - if(free!=2) - iph->id = htons(ip_id_count++); - else - free=1; - - /* All buffers without an owner socket get freed */ - if (sk == NULL) - free = 1; - - skb->free = free; - - /* - * Do we need to fragment. Again this is inefficient. - * We need to somehow lock the original buffer and use - * bits of it. - */ - - if(skb->len > dev->mtu + dev->hard_header_len) - { - ip_fragment(sk,skb,dev,0); - IS_SKB(skb); - kfree_skb(skb,FREE_WRITE); - return; - } - - /* - * Add an IP checksum - */ - - ip_send_check(iph); - - /* - * Print the frame when debugging - */ - - /* - * More debugging. You cannot queue a packet already on a list - * Spot this and moan loudly. - */ - if (skb->next != NULL) - { - printk("ip_queue_xmit: next != NULL\n"); - skb_unlink(skb); - } - - /* - * If a sender wishes the packet to remain unfreed - * we add it to his send queue. This arguably belongs - * in the TCP level since nobody else uses it. BUT - * remember IPng might change all the rules. - */ - - if (!free) - { - unsigned long flags; - /* The socket now has more outstanding blocks */ - - sk->packets_out++; - - /* Protect the list for a moment */ - save_flags(flags); - cli(); - - if (skb->link3 != NULL) - { - printk("ip.c: link3 != NULL\n"); - skb->link3 = NULL; - } - if (sk->send_head == NULL) - { - sk->send_tail = skb; - sk->send_head = skb; - } - else - { - sk->send_tail->link3 = skb; - sk->send_tail = skb; - } - /* skb->link3 is NULL */ - - /* Interrupt restore */ - restore_flags(flags); - } - else - /* Remember who owns the buffer */ - skb->sk = sk; - - /* - * If the indicated interface is up and running, send the packet. - */ - - ip_statistics.IpOutRequests++; -#ifdef CONFIG_IP_ACCT - ip_acct_cnt(iph,dev, ip_acct_chain); -#endif - -#ifdef CONFIG_IP_MULTICAST - - /* - * Multicasts are looped back for other local users - */ - - if (MULTICAST(iph->daddr) && !(dev->flags&IFF_LOOPBACK)) - { - if(sk==NULL || sk->ip_mc_loop) - { - if(iph->daddr==IGMP_ALL_HOSTS) - ip_loopback(dev,skb); - else - { - struct ip_mc_list *imc=dev->ip_mc_list; - while(imc!=NULL) - { - if(imc->multiaddr==iph->daddr) - { - ip_loopback(dev,skb); - break; - } - imc=imc->next; - } - } - } - /* Multicasts with ttl 0 must not go beyond the host */ - - if(skb->ip_hdr->ttl==0) - { - kfree_skb(skb, FREE_READ); - return; - } - } -#endif - if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK)) - ip_loopback(dev,skb); - - if (dev->flags & IFF_UP) - { - /* - * If we have an owner use its priority setting, - * otherwise use NORMAL - */ - - if (sk != NULL) - { - dev_queue_xmit(skb, dev, sk->priority); - } - else - { - dev_queue_xmit(skb, dev, SOPRI_NORMAL); - } - } - else - { - ip_statistics.IpOutDiscards++; - if (free) - kfree_skb(skb, FREE_WRITE); - } -} - - - -#ifdef CONFIG_IP_MULTICAST - -/* - * Write an multicast group list table for the IGMP daemon to - * read. - */ - -int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length) -{ - off_t pos=0, begin=0; - struct ip_mc_list *im; - unsigned long flags; - int len=0; - struct device *dev; - - len=sprintf(buffer,"Device : Count\tGroup Users Timer\n"); - save_flags(flags); - cli(); - - for(dev = dev_base; dev; dev = dev->next) - { - if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)) - { - len+=sprintf(buffer+len,"%-10s: %5d\n", - dev->name, dev->mc_count); - for(im = dev->ip_mc_list; im; im = im->next) - { - len+=sprintf(buffer+len, - "\t\t\t%08lX %5d %d:%08lX\n", - im->multiaddr, im->users, - im->tm_running, im->timer.expires); - pos=begin+len; - if(posoffset+length) - break; - } - } - } - restore_flags(flags); - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - - -#endif -/* - * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on - * an IP socket. - * - * We implement IP_TOS (type of service), IP_TTL (time to live). - * - * Next release we will sort out IP_OPTIONS since for some people are kind of important. - */ - -int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) -{ - int val,err; -#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) - struct ip_fw tmp_fw; -#endif - if (optval == NULL) - return(-EINVAL); - - err=verify_area(VERIFY_READ, optval, sizeof(int)); - if(err) - return err; - - val = get_fs_long((unsigned long *)optval); - - if(level!=SOL_IP) - return -EOPNOTSUPP; - - switch(optname) - { - case IP_TOS: - if(val<0||val>255) - return -EINVAL; - sk->ip_tos=val; - if(val==IPTOS_LOWDELAY) - sk->priority=SOPRI_INTERACTIVE; - if(val==IPTOS_THROUGHPUT) - sk->priority=SOPRI_BACKGROUND; - return 0; - case IP_TTL: - if(val<1||val>255) - return -EINVAL; - sk->ip_ttl=val; - return 0; -#ifdef CONFIG_IP_MULTICAST - case IP_MULTICAST_TTL: - { - unsigned char ucval; - - ucval=get_fs_byte((unsigned char *)optval); - if(ucval<1||ucval>255) - return -EINVAL; - sk->ip_mc_ttl=(int)ucval; - return 0; - } - case IP_MULTICAST_LOOP: - { - unsigned char ucval; - - ucval=get_fs_byte((unsigned char *)optval); - if(ucval!=0 && ucval!=1) - return -EINVAL; - sk->ip_mc_loop=(int)ucval; - return 0; - } - case IP_MULTICAST_IF: - { - /* Not fully tested */ - struct in_addr addr; - struct device *dev=NULL; - - /* - * Check the arguments are allowable - */ - - err=verify_area(VERIFY_READ, optval, sizeof(addr)); - if(err) - return err; - - memcpy_fromfs(&addr,optval,sizeof(addr)); - - printk("MC bind %s\n", in_ntoa(addr.s_addr)); - - /* - * What address has been requested - */ - - if(addr.s_addr==INADDR_ANY) /* Default */ - { - sk->ip_mc_name[0]=0; - return 0; - } - - /* - * Find the device - */ - - for(dev = dev_base; dev; dev = dev->next) - { - if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&& - (dev->pa_addr==addr.s_addr)) - break; - } - - /* - * Did we find one - */ - - if(dev) - { - strcpy(sk->ip_mc_name,dev->name); - return 0; - } - return -EADDRNOTAVAIL; - } - - case IP_ADD_MEMBERSHIP: - { - -/* - * FIXME: Add/Del membership should have a semaphore protecting them from re-entry - */ - struct ip_mreq mreq; - static struct options optmem; - unsigned long route_src; - struct rtable *rt; - struct device *dev=NULL; - - /* - * Check the arguments. - */ - - err=verify_area(VERIFY_READ, optval, sizeof(mreq)); - if(err) - return err; - - memcpy_fromfs(&mreq,optval,sizeof(mreq)); - - /* - * Get device for use later - */ - - if(mreq.imr_interface.s_addr==INADDR_ANY) - { - /* - * Not set so scan. - */ - if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL) - { - dev=rt->rt_dev; - rt->rt_use--; - } - } - else - { - /* - * Find a suitable device. - */ - for(dev = dev_base; dev; dev = dev->next) - { - if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&& - (dev->pa_addr==mreq.imr_interface.s_addr)) - break; - } - } - - /* - * No device, no cookies. - */ - - if(!dev) - return -ENODEV; - - /* - * Join group. - */ - - return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr); - } - - case IP_DROP_MEMBERSHIP: - { - struct ip_mreq mreq; - struct rtable *rt; - static struct options optmem; - unsigned long route_src; - struct device *dev=NULL; - - /* - * Check the arguments - */ - - err=verify_area(VERIFY_READ, optval, sizeof(mreq)); - if(err) - return err; - - memcpy_fromfs(&mreq,optval,sizeof(mreq)); - - /* - * Get device for use later - */ - - if(mreq.imr_interface.s_addr==INADDR_ANY) - { - if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL) - { - dev=rt->rt_dev; - rt->rt_use--; - } - } - else - { - for(dev = dev_base; dev; dev = dev->next) - { - if((dev->flags&IFF_UP)&& (dev->flags&IFF_MULTICAST)&& - (dev->pa_addr==mreq.imr_interface.s_addr)) - break; - } - } - - /* - * Did we find a suitable device. - */ - - if(!dev) - return -ENODEV; - - /* - * Leave group - */ - - return ip_mc_leave_group(sk,dev,mreq.imr_multiaddr.s_addr); - } -#endif -#ifdef CONFIG_IP_FIREWALL - case IP_FW_ADD_BLK: - case IP_FW_DEL_BLK: - case IP_FW_ADD_FWD: - case IP_FW_DEL_FWD: - case IP_FW_CHK_BLK: - case IP_FW_CHK_FWD: - case IP_FW_FLUSH_BLK: - case IP_FW_FLUSH_FWD: - case IP_FW_ZERO_BLK: - case IP_FW_ZERO_FWD: - case IP_FW_POLICY_BLK: - case IP_FW_POLICY_FWD: - if(!suser()) - return -EPERM; - if(optlen>sizeof(tmp_fw) || optlen<1) - return -EINVAL; - err=verify_area(VERIFY_READ,optval,optlen); - if(err) - return err; - memcpy_fromfs(&tmp_fw,optval,optlen); - err=ip_fw_ctl(optname, &tmp_fw,optlen); - return -err; /* -0 is 0 after all */ - -#endif -#ifdef CONFIG_IP_ACCT - case IP_ACCT_DEL: - case IP_ACCT_ADD: - case IP_ACCT_FLUSH: - case IP_ACCT_ZERO: - if(!suser()) - return -EPERM; - if(optlen>sizeof(tmp_fw) || optlen<1) - return -EINVAL; - err=verify_area(VERIFY_READ,optval,optlen); - if(err) - return err; - memcpy_fromfs(&tmp_fw, optval,optlen); - err=ip_acct_ctl(optname, &tmp_fw,optlen); - return -err; /* -0 is 0 after all */ -#endif - /* IP_OPTIONS and friends go here eventually */ - default: - return(-ENOPROTOOPT); - } -} - -/* - * Get the options. Note for future reference. The GET of IP options gets the - * _received_ ones. The set sets the _sent_ ones. - */ - -int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) -{ - int val,err; -#ifdef CONFIG_IP_MULTICAST - int len; -#endif - - if(level!=SOL_IP) - return -EOPNOTSUPP; - - switch(optname) - { - case IP_TOS: - val=sk->ip_tos; - break; - case IP_TTL: - val=sk->ip_ttl; - break; -#ifdef CONFIG_IP_MULTICAST - case IP_MULTICAST_TTL: - val=sk->ip_mc_ttl; - break; - case IP_MULTICAST_LOOP: - val=sk->ip_mc_loop; - break; - case IP_MULTICAST_IF: - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; - len=strlen(sk->ip_mc_name); - err=verify_area(VERIFY_WRITE, optval, len); - if(err) - return err; - put_fs_long(len,(unsigned long *) optlen); - memcpy_tofs((void *)optval,sk->ip_mc_name, len); - return 0; -#endif - default: - return(-ENOPROTOOPT); - } - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; - put_fs_long(sizeof(int),(unsigned long *) optlen); - - err=verify_area(VERIFY_WRITE, optval, sizeof(int)); - if(err) - return err; - put_fs_long(val,(unsigned long *)optval); - - return(0); -} - -/* - * IP protocol layer initialiser - */ - -static struct packet_type ip_packet_type = -{ - 0, /* MUTTER ntohs(ETH_P_IP),*/ - NULL, /* All devices */ - ip_rcv, - NULL, - NULL, -}; - -/* - * Device notifier - */ - -static int ip_rt_event(unsigned long event, void *ptr) -{ - if(event==NETDEV_DOWN) - ip_rt_flush(ptr); - return NOTIFY_DONE; -} - -struct notifier_block ip_rt_notifier={ - ip_rt_event, - NULL, - 0 -}; - -/* - * IP registers the packet type and then calls the subprotocol initialisers - */ - -void ip_init(void) -{ - ip_packet_type.type=htons(ETH_P_IP); - dev_add_pack(&ip_packet_type); - - /* So we flush routes when a device is downed */ - register_netdevice_notifier(&ip_rt_notifier); -/* ip_raw_init(); - ip_packet_init(); - ip_tcp_init(); - ip_udp_init();*/ -} diff --git a/pfinet/linux-inet/ip.h b/pfinet/linux-inet/ip.h deleted file mode 100644 index 95954a8c..00000000 --- a/pfinet/linux-inet/ip.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP module. - * - * Version: @(#)ip.h 1.0.2 05/07/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Alan Cox, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _IP_H -#define _IP_H - - -#include -#include - -#ifndef _SNMP_H -#include "snmp.h" -#endif - -#include "sock.h" /* struct sock */ - -/* IP flags. */ -#define IP_CE 0x8000 /* Flag: "Congestion" */ -#define IP_DF 0x4000 /* Flag: "Don't Fragment" */ -#define IP_MF 0x2000 /* Flag: "More Fragments" */ -#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */ - -#define IP_FRAG_TIME (30 * HZ) /* fragment lifetime */ - -#ifdef CONFIG_IP_MULTICAST -extern void ip_mc_dropsocket(struct sock *); -extern void ip_mc_dropdevice(struct device *dev); -extern int ip_mc_procinfo(char *, char **, off_t, int); -#define MULTICAST(x) (IN_MULTICAST(htonl(x))) -#endif - - -/* Describe an IP fragment. */ -struct ipfrag { - int offset; /* offset of fragment in IP datagram */ - int end; /* last byte of data in datagram */ - int len; /* length of this fragment */ - struct sk_buff *skb; /* complete received fragment */ - unsigned char *ptr; /* pointer into real fragment data */ - struct ipfrag *next; /* linked list pointers */ - struct ipfrag *prev; -}; - -/* Describe an entry in the "incomplete datagrams" queue. */ -struct ipq { - unsigned char *mac; /* pointer to MAC header */ - struct iphdr *iph; /* pointer to IP header */ - int len; /* total length of original datagram */ - short ihlen; /* length of the IP header */ - short maclen; /* length of the MAC header */ - struct timer_list timer; /* when will this queue expire? */ - struct ipfrag *fragments; /* linked list of received fragments */ - struct ipq *next; /* linked list pointers */ - struct ipq *prev; - struct device *dev; /* Device - for icmp replies */ -}; - - -extern int backoff(int n); - -extern void ip_print(const struct iphdr *ip); -extern int ip_ioctl(struct sock *sk, int cmd, - unsigned long arg); -extern void ip_route_check(unsigned long daddr); -extern int ip_build_header(struct sk_buff *skb, - unsigned long saddr, - unsigned long daddr, - struct device **dev, int type, - struct options *opt, int len, - int tos,int ttl); -extern unsigned short ip_compute_csum(unsigned char * buff, int len); -extern int ip_rcv(struct sk_buff *skb, struct device *dev, - struct packet_type *pt); -extern void ip_send_check(struct iphdr *ip); -extern int ip_id_count; -extern void ip_queue_xmit(struct sock *sk, - struct device *dev, struct sk_buff *skb, - int free); -extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen); -extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen); -extern void ip_init(void); - -extern struct ip_mib ip_statistics; - -/* - * This is a version of ip_compute_csum() optimized for IP headers, which - * always checksum on 4 octet boundaries. - * Used by ip.c and slhc.c (the net driver module) - * (Moved to here by bj0rn@blox.se) - */ - -static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen) -{ - unsigned long sum = 0; - - if (wlen) - { - unsigned long bogus; - __asm__("clc\n" - "1:\t" - "lodsl\n\t" - "adcl %3, %0\n\t" - "decl %2\n\t" - "jne 1b\n\t" - "adcl $0, %0\n\t" - "movl %0, %3\n\t" - "shrl $16, %3\n\t" - "addw %w3, %w0\n\t" - "adcw $0, %w0" - : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus) - : "0" (sum), "1" (buff), "2" (wlen)); - } - return (~sum) & 0xffff; -} -#endif /* _IP_H */ diff --git a/pfinet/linux-inet/ip_fw.c b/pfinet/linux-inet/ip_fw.c deleted file mode 100644 index 0572c8f1..00000000 --- a/pfinet/linux-inet/ip_fw.c +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * IP firewalling code. This is taken from 4.4BSD. Please note the - * copyright message below. As per the GPL it must be maintained - * and the licenses thus do not conflict. While this port is subject - * to the GPL I also place my modifications under the original - * license in recognition of the original copyright. - * -- Alan Cox. - * - * Ported from BSD to Linux, - * Alan Cox 22/Nov/1994. - * Zeroing /proc and other additions - * Jos Vos 4/Feb/1995. - * Merged and included the FreeBSD-Current changes at Ugen's request - * (but hey it's a lot cleaner now). Ugen would prefer in some ways - * we waited for his final product but since Linux 1.2.0 is about to - * appear it's not practical - Read: It works, it's not clean but please - * don't consider it to be his standard of finished work. - * Alan Cox 12/Feb/1995 - * Porting bidirectional entries from BSD, fixing accounting issues, - * adding struct ip_fwpkt for checking packets with interface address - * Jos Vos 5/Mar/1995. - * - * All the real work was done by ..... - */ - -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include "route.h" -#include "tcp.h" -#include -#include "sock.h" -#include "icmp.h" -#include - -/* - * Implement IP packet firewall - */ - -#ifdef CONFIG_IPFIREWALL_DEBUG -#define dprintf1(a) printk(a) -#define dprintf2(a1,a2) printk(a1,a2) -#define dprintf3(a1,a2,a3) printk(a1,a2,a3) -#define dprintf4(a1,a2,a3,a4) printk(a1,a2,a3,a4) -#else -#define dprintf1(a) -#define dprintf2(a1,a2) -#define dprintf3(a1,a2,a3) -#define dprintf4(a1,a2,a3,a4) -#endif - -#define print_ip(a) printf("%d.%d.%d.%d",(ntohl(a.s_addr)>>24)&0xFF,\ - (ntohl(a.s_addr)>>16)&0xFF,\ - (ntohl(a.s_addr)>>8)&0xFF,\ - (ntohl(a.s_addr))&0xFF); - -#ifdef IPFIREWALL_DEBUG -#define dprint_ip(a) print_ip(a) -#else -#define dprint_ip(a) -#endif - -#ifdef CONFIG_IP_FIREWALL -struct ip_fw *ip_fw_fwd_chain; -struct ip_fw *ip_fw_blk_chain; -int ip_fw_blk_policy=IP_FW_F_ACCEPT; -int ip_fw_fwd_policy=IP_FW_F_ACCEPT; -#endif -#ifdef CONFIG_IP_ACCT -struct ip_fw *ip_acct_chain; -#endif - -#define IP_INFO_BLK 0 -#define IP_INFO_FWD 1 -#define IP_INFO_ACCT 2 - - -/* - * Returns 1 if the port is matched by the vector, 0 otherwise - */ - -extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag) -{ - if (!nports) - return 1; - if ( range_flag ) - { - if ( portptr[0] <= port && port <= portptr[1] ) - { - return( 1 ); - } - nports -= 2; - portptr += 2; - } - while ( nports-- > 0 ) - { - if ( *portptr++ == port ) - { - return( 1 ); - } - } - return(0); -} - -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) - - -/* - * Returns 0 if packet should be dropped, 1 if it should be accepted, - * and -1 if an ICMP host unreachable packet should be sent. - * Also does accounting so you can feed it the accounting chain. - * If opt is set to 1, it means that we do this for accounting - * purposes (searches all entries and handles fragments different). - * If opt is set to 2, it doesn't count a matching packet, which - * is used when calling this for checking purposes (IP_FW_CHK_*). - */ - - -int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int policy, int opt) -{ - struct ip_fw *f; - struct tcphdr *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl); - struct udphdr *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl); - __u32 src, dst; - __u16 src_port=0, dst_port=0; - unsigned short f_prt=0, prt; - char notcpsyn=1, frag1, match; - unsigned short f_flag; - - /* - * If the chain is empty follow policy. The BSD one - * accepts anything giving you a time window while - * flushing and rebuilding the tables. - */ - - src = ip->saddr; - dst = ip->daddr; - - /* - * This way we handle fragmented packets. - * we ignore all fragments but the first one - * so the whole packet can't be reassembled. - * This way we relay on the full info which - * stored only in first packet. - * - * Note that this theoretically allows partial packet - * spoofing. Not very dangerous but paranoid people may - * wish to play with this. It also allows the so called - * "fragment bomb" denial of service attack on some types - * of system. - */ - - frag1 = ((ntohs(ip->frag_off) & IP_OFFSET) == 0); - if (!frag1 && (opt != 1) && (ip->protocol == IPPROTO_TCP || - ip->protocol == IPPROTO_UDP)) - return(1); - - src = ip->saddr; - dst = ip->daddr; - - /* - * If we got interface from which packet came - * we can use the address directly. This is unlike - * 4.4BSD derived systems that have an address chain - * per device. We have a device per address with dummy - * devices instead. - */ - - dprintf1("Packet "); - switch(ip->protocol) - { - case IPPROTO_TCP: - dprintf1("TCP "); - /* ports stay 0 if it is not the first fragment */ - if (frag1) { - src_port=ntohs(tcp->source); - dst_port=ntohs(tcp->dest); - if(tcp->syn && !tcp->ack) - /* We *DO* have SYN, value FALSE */ - notcpsyn=0; - } - prt=IP_FW_F_TCP; - break; - case IPPROTO_UDP: - dprintf1("UDP "); - /* ports stay 0 if it is not the first fragment */ - if (frag1) { - src_port=ntohs(udp->source); - dst_port=ntohs(udp->dest); - } - prt=IP_FW_F_UDP; - break; - case IPPROTO_ICMP: - dprintf2("ICMP:%d ",((char *)portptr)[0]&0xff); - prt=IP_FW_F_ICMP; - break; - default: - dprintf2("p=%d ",ip->protocol); - prt=IP_FW_F_ALL; - break; - } - dprint_ip(ip->saddr); - - if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) - /* This will print 0 when it is not the first fragment! */ - dprintf2(":%d ", src_port); - dprint_ip(ip->daddr); - if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) - /* This will print 0 when it is not the first fragment! */ - dprintf2(":%d ",dst_port); - dprintf1("\n"); - - for (f=chain;f;f=f->fw_next) - { - /* - * This is a bit simpler as we don't have to walk - * an interface chain as you do in BSD - same logic - * however. - */ - - /* - * Match can become 0x01 (a "normal" match was found), - * 0x02 (a reverse match was found), and 0x03 (the - * IP addresses match in both directions). - * Now we know in which direction(s) we should look - * for a match for the TCP/UDP ports. Both directions - * might match (e.g., when both addresses are on the - * same network for which an address/mask is given), but - * the ports might only match in one direction. - * This was obviously wrong in the original BSD code. - */ - match = 0x00; - - if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr - && (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr) - /* normal direction */ - match |= 0x01; - - if ((f->fw_flg & IP_FW_F_BIDIR) && - (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr - && (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr) - /* reverse direction */ - match |= 0x02; - - if (match) - { - /* - * Look for a VIA match - */ - if(f->fw_via.s_addr && rif) - { - if(rif->pa_addr!=f->fw_via.s_addr) - continue; /* Mismatch */ - } - /* - * Drop through - this is a match - */ - } - else - continue; - - /* - * Ok the chain addresses match. - */ - - f_prt=f->fw_flg&IP_FW_F_KIND; - if (f_prt!=IP_FW_F_ALL) - { - /* - * This is actually buggy as if you set SYN flag - * on UDP or ICMP firewall it will never work,but - * actually it is a concern of software which sets - * firewall entries. - */ - - if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn) - continue; - /* - * Specific firewall - packet's protocol - * must match firewall's. - */ - - if(prt!=f_prt) - continue; - - if(!(prt==IP_FW_F_ICMP || ((match & 0x01) && - port_match(&f->fw_pts[0], f->fw_nsp, src_port, - f->fw_flg&IP_FW_F_SRNG) && - port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port, - f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) && - port_match(&f->fw_pts[0], f->fw_nsp, dst_port, - f->fw_flg&IP_FW_F_SRNG) && - port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port, - f->fw_flg&IP_FW_F_DRNG)))) - { - continue; - } - } -#ifdef CONFIG_IP_FIREWALL_VERBOSE - /* - * VERY ugly piece of code which actually - * makes kernel printf for denied packets... - */ - - if (f->fw_flg & IP_FW_F_PRN) - { - if(opt != 1) { - if(f->fw_flg&IP_FW_F_ACCEPT) - printk("Accept "); - else if(f->fw_flg&IP_FW_F_ICMPRPL) - printk("Reject "); - else - printk("Deny "); - } - switch(ip->protocol) - { - case IPPROTO_TCP: - printk("TCP "); - break; - case IPPROTO_UDP: - printk("UDP "); - case IPPROTO_ICMP: - printk("ICMP "); - break; - default: - printk("p=%d ",ip->protocol); - break; - } - print_ip(ip->saddr); - if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) - printk(":%d", src_port); - printk(" "); - print_ip(ip->daddr); - if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) - printk(":%d",dst_port); - printk("\n"); - } -#endif - if (opt != 2) { - f->fw_bcnt+=ntohs(ip->tot_len); - f->fw_pcnt++; - } - if (opt != 1) - break; - } /* Loop */ - - if(opt == 1) - return 0; - - /* - * We rely on policy defined in the rejecting entry or, if no match - * was found, we rely on the general policy variable for this type - * of firewall. - */ - - if(f!=NULL) /* A match was found */ - f_flag=f->fw_flg; - else - f_flag=policy; - if(f_flag&IP_FW_F_ACCEPT) - return 1; - if(f_flag&IP_FW_F_ICMPRPL) - return -1; - return 0; -} - - -static void zero_fw_chain(struct ip_fw *chainptr) -{ - struct ip_fw *ctmp=chainptr; - while(ctmp) - { - ctmp->fw_pcnt=0L; - ctmp->fw_bcnt=0L; - ctmp=ctmp->fw_next; - } -} - -static void free_fw_chain(struct ip_fw *volatile* chainptr) -{ - unsigned long flags; - save_flags(flags); - cli(); - while ( *chainptr != NULL ) - { - struct ip_fw *ftmp; - ftmp = *chainptr; - *chainptr = ftmp->fw_next; - kfree_s(ftmp,sizeof(*ftmp)); - } - restore_flags(flags); -} - -/* Volatiles to keep some of the compiler versions amused */ - -static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl) -{ - struct ip_fw *ftmp; - struct ip_fw *chtmp=NULL; - struct ip_fw *volatile chtmp_prev=NULL; - unsigned long flags; - unsigned long m_src_mask,m_dst_mask; - unsigned long n_sa,n_da,o_sa,o_da,o_sm,o_dm,n_sm,n_dm; - unsigned short n_sr,n_dr,o_sr,o_dr; - unsigned short oldkind,newkind; - int addb4=0; - int n_o,n_n; - - save_flags(flags); - - ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC ); - if ( ftmp == NULL ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: malloc said no\n"); -#endif - return( ENOMEM ); - } - - memcpy(ftmp, frwl, sizeof( struct ip_fw ) ); - - ftmp->fw_pcnt=0L; - ftmp->fw_bcnt=0L; - - ftmp->fw_next = NULL; - - cli(); - - if (*chainptr==NULL) - { - *chainptr=ftmp; - } - else - { - chtmp_prev=NULL; - for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) - { - addb4=0; - newkind=ftmp->fw_flg & IP_FW_F_KIND; - oldkind=chtmp->fw_flg & IP_FW_F_KIND; - - if (newkind!=IP_FW_F_ALL - && oldkind!=IP_FW_F_ALL - && oldkind!=newkind) - { - chtmp_prev=chtmp; - continue; - } - - /* - * Very very *UGLY* code... - * Sorry,but i had to do this.... - */ - - n_sa=ntohl(ftmp->fw_src.s_addr); - n_da=ntohl(ftmp->fw_dst.s_addr); - n_sm=ntohl(ftmp->fw_smsk.s_addr); - n_dm=ntohl(ftmp->fw_dmsk.s_addr); - - o_sa=ntohl(chtmp->fw_src.s_addr); - o_da=ntohl(chtmp->fw_dst.s_addr); - o_sm=ntohl(chtmp->fw_smsk.s_addr); - o_dm=ntohl(chtmp->fw_dmsk.s_addr); - - m_src_mask = o_sm & n_sm; - m_dst_mask = o_dm & n_dm; - - if ((o_sa & m_src_mask) == (n_sa & m_src_mask)) - { - if (n_sm > o_sm) - addb4++; - if (n_sm < o_sm) - addb4--; - } - - if ((o_da & m_dst_mask) == (n_da & m_dst_mask)) - { - if (n_dm > o_dm) - addb4++; - if (n_dm < o_dm) - addb4--; - } - - if (((o_da & o_dm) == (n_da & n_dm)) - &&((o_sa & o_sm) == (n_sa & n_sm))) - { - if (newkind!=IP_FW_F_ALL && - oldkind==IP_FW_F_ALL) - addb4++; - if (newkind==oldkind && (oldkind==IP_FW_F_TCP - || oldkind==IP_FW_F_UDP)) - { - - /* - * Here the main idea is to check the size - * of port range which the frwl covers - * We actually don't check their values but - * just the wideness of range they have - * so that less wide ranges or single ports - * go first and wide ranges go later. No ports - * at all treated as a range of maximum number - * of ports. - */ - - if (ftmp->fw_flg & IP_FW_F_SRNG) - n_sr=ftmp->fw_pts[1]-ftmp->fw_pts[0]; - else - n_sr=(ftmp->fw_nsp)? - ftmp->fw_nsp : 0xFFFF; - - if (chtmp->fw_flg & IP_FW_F_SRNG) - o_sr=chtmp->fw_pts[1]-chtmp->fw_pts[0]; - else - o_sr=(chtmp->fw_nsp)?chtmp->fw_nsp : 0xFFFF; - - if (n_sro_sr) - addb4--; - - n_n=ftmp->fw_nsp; - n_o=chtmp->fw_nsp; - - /* - * Actually this cannot happen as the frwl control - * procedure checks for number of ports in source and - * destination range but we will try to be more safe. - */ - - if ((n_n>(IP_FW_MAX_PORTS-2)) || - (n_o>(IP_FW_MAX_PORTS-2))) - goto skip_check; - - if (ftmp->fw_flg & IP_FW_F_DRNG) - n_dr=ftmp->fw_pts[n_n+1]-ftmp->fw_pts[n_n]; - else - n_dr=(ftmp->fw_ndp)? ftmp->fw_ndp : 0xFFFF; - - if (chtmp->fw_flg & IP_FW_F_DRNG) - o_dr=chtmp->fw_pts[n_o+1]-chtmp->fw_pts[n_o]; - else - o_dr=(chtmp->fw_ndp)? chtmp->fw_ndp : 0xFFFF; - if (n_dro_dr) - addb4--; -skip_check: - } - /* finally look at the interface address */ - if ((addb4 == 0) && ftmp->fw_via.s_addr && - !(chtmp->fw_via.s_addr)) - addb4++; - } - if (addb4>0) - { - if (chtmp_prev) - { - chtmp_prev->fw_next=ftmp; - ftmp->fw_next=chtmp; - } - else - { - *chainptr=ftmp; - ftmp->fw_next=chtmp; - } - restore_flags(flags); - return 0; - } - chtmp_prev=chtmp; - } - } - - if (chtmp_prev) - chtmp_prev->fw_next=ftmp; - else - *chainptr=ftmp; - restore_flags(flags); - return(0); -} - -static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl) -{ - struct ip_fw *ftmp,*ltmp; - unsigned short tport1,tport2,tmpnum; - char matches,was_found; - unsigned long flags; - - save_flags(flags); - cli(); - - ftmp=*chainptr; - - if ( ftmp == NULL ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: chain is empty\n"); -#endif - restore_flags(flags); - return( EINVAL ); - } - - ltmp=NULL; - was_found=0; - - while( ftmp != NULL ) - { - matches=1; - if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr - || ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr - || ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr - || ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr - || ftmp->fw_via.s_addr!=frwl->fw_via.s_addr - || ftmp->fw_flg!=frwl->fw_flg) - matches=0; - - tport1=ftmp->fw_nsp+ftmp->fw_ndp; - tport2=frwl->fw_nsp+frwl->fw_ndp; - if (tport1!=tport2) - matches=0; - else if (tport1!=0) - { - for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++) - if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum]) - matches=0; - } - if(matches) - { - was_found=1; - if (ltmp) - { - ltmp->fw_next=ftmp->fw_next; - kfree_s(ftmp,sizeof(*ftmp)); - ftmp=ltmp->fw_next; - } - else - { - *chainptr=ftmp->fw_next; - kfree_s(ftmp,sizeof(*ftmp)); - ftmp=*chainptr; - } - } - else - { - ltmp = ftmp; - ftmp = ftmp->fw_next; - } - } - restore_flags(flags); - if (was_found) - return 0; - else - return(EINVAL); -} - -#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */ - -struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len) -{ - - if ( len != sizeof(struct ip_fw) ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: len=%d, want %d\n",m->m_len, - sizeof(struct ip_fw)); -#endif - return(NULL); - } - - if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n", - frwl->fw_flg); -#endif - return(NULL); - } - - if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: src range set but n_src_p=%d\n", - frwl->fw_nsp); -#endif - return(NULL); - } - - if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: dst range set but n_dst_p=%d\n", - frwl->fw_ndp); -#endif - return(NULL); - } - - if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: too many ports (%d+%d)\n", - frwl->fw_nsp,frwl->fw_ndp); -#endif - return(NULL); - } - - return frwl; -} - - - - -#ifdef CONFIG_IP_ACCT - -void ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f) -{ - (void) ip_fw_chk(iph, dev, f, 0, 1); - return; -} - -int ip_acct_ctl(int stage, void *m, int len) -{ - if ( stage == IP_ACCT_FLUSH ) - { - free_fw_chain(&ip_acct_chain); - return(0); - } - if ( stage == IP_ACCT_ZERO ) - { - zero_fw_chain(ip_acct_chain); - return(0); - } - if ( stage == IP_ACCT_ADD - || stage == IP_ACCT_DEL - ) - { - struct ip_fw *frwl; - - if (!(frwl=check_ipfw_struct(m,len))) - return (EINVAL); - - switch (stage) - { - case IP_ACCT_ADD: - return( add_to_chain(&ip_acct_chain,frwl)); - case IP_ACCT_DEL: - return( del_from_chain(&ip_acct_chain,frwl)); - default: - /* - * Should be panic but... (Why ??? - AC) - */ -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_acct_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); - } - } -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_acct_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); -} -#endif - -#ifdef CONFIG_IP_FIREWALL -int ip_fw_ctl(int stage, void *m, int len) -{ - int ret; - - if ( stage == IP_FW_FLUSH_BLK ) - { - free_fw_chain(&ip_fw_blk_chain); - return(0); - } - - if ( stage == IP_FW_FLUSH_FWD ) - { - free_fw_chain(&ip_fw_fwd_chain); - return(0); - } - - if ( stage == IP_FW_ZERO_BLK ) - { - zero_fw_chain(ip_fw_blk_chain); - return(0); - } - - if ( stage == IP_FW_ZERO_FWD ) - { - zero_fw_chain(ip_fw_fwd_chain); - return(0); - } - - if ( stage == IP_FW_POLICY_BLK || stage == IP_FW_POLICY_FWD ) - { - int *tmp_policy_ptr; - tmp_policy_ptr=(int *)m; - if ( stage == IP_FW_POLICY_BLK ) - ip_fw_blk_policy=*tmp_policy_ptr; - else - ip_fw_fwd_policy=*tmp_policy_ptr; - return 0; - } - - if ( stage == IP_FW_CHK_BLK || stage == IP_FW_CHK_FWD ) - { - struct device viadev; - struct ip_fwpkt *ipfwp; - struct iphdr *ip; - - if ( len < sizeof(struct ip_fwpkt) ) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: length=%d, expected %d\n", - len, sizeof(struct ip_fwpkt)); -#endif - return( EINVAL ); - } - - ipfwp = (struct ip_fwpkt *)m; - ip = &(ipfwp->fwp_iph); - - if ( ip->ihl != sizeof(struct iphdr) / sizeof(int)) - { -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl, - sizeof(struct ip)/sizeof(int)); -#endif - return(EINVAL); - } - - viadev.pa_addr = ipfwp->fwp_via.s_addr; - - if ((ret = ip_fw_chk(ip, &viadev, - stage == IP_FW_CHK_BLK ? - ip_fw_blk_chain : ip_fw_fwd_chain, - stage == IP_FW_CHK_BLK ? - ip_fw_blk_policy : ip_fw_fwd_policy, 2 )) > 0 - ) - return(0); - else if (ret == -1) - return(ECONNREFUSED); - else - return(ETIMEDOUT); - } - -/* - * Here we really working hard-adding new elements - * to blocking/forwarding chains or deleting 'em - */ - - if ( stage == IP_FW_ADD_BLK || stage == IP_FW_ADD_FWD - || stage == IP_FW_DEL_BLK || stage == IP_FW_DEL_FWD - ) - { - struct ip_fw *frwl; - frwl=check_ipfw_struct(m,len); - if (frwl==NULL) - return (EINVAL); - - switch (stage) - { - case IP_FW_ADD_BLK: - return(add_to_chain(&ip_fw_blk_chain,frwl)); - case IP_FW_ADD_FWD: - return(add_to_chain(&ip_fw_fwd_chain,frwl)); - case IP_FW_DEL_BLK: - return(del_from_chain(&ip_fw_blk_chain,frwl)); - case IP_FW_DEL_FWD: - return(del_from_chain(&ip_fw_fwd_chain,frwl)); - default: - /* - * Should be panic but... (Why are BSD people panic obsessed ??) - */ -#ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); - } - } - -#ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); -} -#endif /* CONFIG_IP_FIREWALL */ - -#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) - -static int ip_chain_procinfo(int stage, char *buffer, char **start, - off_t offset, int length, int reset) -{ - off_t pos=0, begin=0; - struct ip_fw *i; - unsigned long flags; - int len, p; - - - switch(stage) - { -#ifdef CONFIG_IP_FIREWALL - case IP_INFO_BLK: - i = ip_fw_blk_chain; - len=sprintf(buffer, "IP firewall block rules, default %d\n", - ip_fw_blk_policy); - break; - case IP_INFO_FWD: - i = ip_fw_fwd_chain; - len=sprintf(buffer, "IP firewall forward rules, default %d\n", - ip_fw_fwd_policy); - break; -#endif -#ifdef CONFIG_IP_ACCT - case IP_INFO_ACCT: - i = ip_acct_chain; - len=sprintf(buffer,"IP accounting rules\n"); - break; -#endif - default: - /* this should never be reached, but safety first... */ - i = NULL; - len=0; - break; - } - - save_flags(flags); - cli(); - - while(i!=NULL) - { - len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %08lX %X ", - ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr), - ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr), - ntohl(i->fw_via.s_addr),i->fw_flg); - len+=sprintf(buffer+len,"%u %u %lu %lu", - i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt); - for (p = 0; p < IP_FW_MAX_PORTS; p++) - len+=sprintf(buffer+len, " %u", i->fw_pts[p]); - buffer[len++]='\n'; - buffer[len]='\0'; - pos=begin+len; - if(posfw_pcnt=0L; - i->fw_bcnt=0L; - } - if(pos>offset+length) - break; - i=i->fw_next; - } - restore_flags(flags); - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} -#endif - -#ifdef CONFIG_IP_ACCT - -int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length, int reset) -{ - return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,reset); -} - -#endif - -#ifdef CONFIG_IP_FIREWALL - -int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length, int reset) -{ - return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,reset); -} - -int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length, int reset) -{ - return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,reset); -} - -#endif diff --git a/pfinet/linux-inet/ipx.c b/pfinet/linux-inet/ipx.c deleted file mode 100644 index 88b53c30..00000000 --- a/pfinet/linux-inet/ipx.c +++ /dev/null @@ -1,1947 +0,0 @@ -/* - * Implements an IPX socket layer (badly - but I'm working on it). - * - * This code is derived from work by - * Ross Biro : Writing the original IP stack - * Fred Van Kempen : Tidying up the TCP/IP - * - * Many thanks go to Keith Baker, Institute For Industrial Information - * Technology Ltd, Swansea University for allowing me to work on this - * in my own time even though it was in some ways related to commercial - * work I am currently employed to do there. - * - * All the material in this file is subject to the Gnu license version 2. - * Neither Alan Cox nor the Swansea University Computer Society admit liability - * nor provide warranty for any of this software. This material is provided - * as is and at no charge. - * - * Revision 0.21: Uses the new generic socket option code. - * Revision 0.22: Gcc clean ups and drop out device registration. Use the - * new multi-protocol edition of hard_header - * Revision 0.23: IPX /proc by Mark Evans. - * Adding a route will overwrite any existing route to the same - * network. - * Revision 0.24: Supports new /proc with no 4K limit - * Revision 0.25: Add ephemeral sockets, passive local network - * identification, support for local net 0 and - * multiple datalinks - * Revision 0.26: Device drop kills IPX routes via it. (needed for modules) - * Revision 0.27: Autobind - * Revision 0.28: Small fix for multiple local networks - * Revision 0.29: Assorted major errors removed - * Small correction to promisc mode error fix - * Asynchronous I/O support. - * Changed to use notifiers and the newer packet_type stuff. - * Assorted major fixes - * - * Portions Copyright (c) 1995 Caldera, Inc. - * Neither Greg Page nor Caldera, Inc. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sock.h" -#include -#include -#include -#include -#include /* For TIOCOUTQ/INQ */ -#include -#include "p8022.h" -#include "psnap.h" - -#ifdef CONFIG_IPX -/* Configuration Variables */ -static unsigned char ipxcfg_max_hops = 16; -static char ipxcfg_auto_select_primary = 0; -static char ipxcfg_auto_create_interfaces = 0; - -/* Global Variables */ -static struct datalink_proto *p8022_datalink = NULL; -static struct datalink_proto *pEII_datalink = NULL; -static struct datalink_proto *p8023_datalink = NULL; -static struct datalink_proto *pSNAP_datalink = NULL; - -static ipx_interface *ipx_interfaces = NULL; -static ipx_route *ipx_routes = NULL; -static ipx_interface *ipx_internal_net = NULL; -static ipx_interface *ipx_primary_net = NULL; - -static int -ipxcfg_set_auto_create(char val) -{ - ipxcfg_auto_create_interfaces = val; - return 0; -} - -static int -ipxcfg_set_auto_select(char val) -{ - ipxcfg_auto_select_primary = val; - if (val && (ipx_primary_net == NULL)) - ipx_primary_net = ipx_interfaces; - return 0; -} - -static int -ipxcfg_get_config_data(ipx_config_data *arg) -{ - ipx_config_data vals; - - vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces; - vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary; - memcpy_tofs(arg, &vals, sizeof(vals)); - return 0; -} - - -/***********************************************************************************************************************\ -* * -* Handlers for the socket list. * -* * -\***********************************************************************************************************************/ - -/* - * Note: Sockets may not be removed _during_ an interrupt or inet_bh - * handler using this technique. They can be added although we do not - * use this facility. - */ - -static void -ipx_remove_socket(ipx_socket *sk) -{ - ipx_socket *s; - ipx_interface *intrfc; - unsigned long flags; - - save_flags(flags); - cli(); - - /* Determine interface with which socket is associated */ - intrfc = sk->ipx_intrfc; - if (intrfc == NULL) { - restore_flags(flags); - return; - } - - s=intrfc->if_sklist; - if(s==sk) { - intrfc->if_sklist=s->next; - restore_flags(flags); - return; - } - - while(s && s->next) { - if(s->next==sk) { - s->next=sk->next; - restore_flags(flags); - return; - } - s=s->next; - } - restore_flags(flags); -} - -/* - * This is only called from user mode. Thus it protects itself against - * interrupt users but doesn't worry about being called during work. - * Once it is removed from the queue no interrupt or bottom half will - * touch it and we are (fairly 8-) ) safe. - */ - -static void -ipx_destroy_socket(ipx_socket *sk) -{ - struct sk_buff *skb; - - ipx_remove_socket(sk); - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { - kfree_skb(skb,FREE_READ); - } - - kfree_s(sk,sizeof(*sk)); -} - -/* The following code is used to support IPX Interfaces (IPXITF). An - * IPX interface is defined by a physical device and a frame type. - */ - -static ipx_route * ipxrtr_lookup(unsigned long); - -static void -ipxitf_clear_primary_net(void) -{ - if (ipxcfg_auto_select_primary && (ipx_interfaces != NULL)) - ipx_primary_net = ipx_interfaces; - else - ipx_primary_net = NULL; -} - -static ipx_interface * -ipxitf_find_using_phys(struct device *dev, unsigned short datalink) -{ - ipx_interface *i; - - for (i=ipx_interfaces; - i && ((i->if_dev!=dev) || (i->if_dlink_type!=datalink)); - i=i->if_next) - ; - return i; -} - -static ipx_interface * -ipxitf_find_using_net(unsigned long net) -{ - ipx_interface *i; - - if (net == 0L) - return ipx_primary_net; - - for (i=ipx_interfaces; i && (i->if_netnum!=net); i=i->if_next) - ; - - return i; -} - -/* Sockets are bound to a particular IPX interface. */ -static void -ipxitf_insert_socket(ipx_interface *intrfc, ipx_socket *sk) -{ - ipx_socket *s; - - sk->ipx_intrfc = intrfc; - sk->next = NULL; - if (intrfc->if_sklist == NULL) { - intrfc->if_sklist = sk; - } else { - for (s = intrfc->if_sklist; s->next != NULL; s = s->next) - ; - s->next = sk; - } -} - -static ipx_socket * -ipxitf_find_socket(ipx_interface *intrfc, unsigned short port) -{ - ipx_socket *s; - - for (s=intrfc->if_sklist; - (s != NULL) && (s->ipx_port != port); - s=s->next) - ; - - return s; -} - -static void ipxrtr_del_routes(ipx_interface *); - -static void -ipxitf_down(ipx_interface *intrfc) -{ - ipx_interface *i; - ipx_socket *s, *t; - - /* Delete all routes associated with this interface */ - ipxrtr_del_routes(intrfc); - - /* error sockets */ - for (s = intrfc->if_sklist; s != NULL; ) { - s->err = ENOLINK; - s->error_report(s); - s->ipx_intrfc = NULL; - s->ipx_port = 0; - s->zapped=1; /* Indicates it is no longer bound */ - t = s; - s = s->next; - t->next = NULL; - } - intrfc->if_sklist = NULL; - - /* remove this interface from list */ - if (intrfc == ipx_interfaces) { - ipx_interfaces = intrfc->if_next; - } else { - for (i = ipx_interfaces; - (i != NULL) && (i->if_next != intrfc); - i = i->if_next) - ; - if ((i != NULL) && (i->if_next == intrfc)) - i->if_next = intrfc->if_next; - } - - /* remove this interface from *special* networks */ - if (intrfc == ipx_primary_net) - ipxitf_clear_primary_net(); - if (intrfc == ipx_internal_net) - ipx_internal_net = NULL; - - kfree_s(intrfc, sizeof(*intrfc)); -} - -static int -ipxitf_device_event(unsigned long event, void *ptr) -{ - struct device *dev = ptr; - ipx_interface *i, *tmp; - - if(event!=NETDEV_DOWN) - return NOTIFY_DONE; - - for (i = ipx_interfaces; i != NULL; ) { - - tmp = i->if_next; - if (i->if_dev == dev) - ipxitf_down(i); - i = tmp; - - } - - return NOTIFY_DONE; -} - -static int -ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb) -{ - int retval; - - if((retval = sock_queue_rcv_skb(sock, skb))<0) { - /* - * We do a FREE_WRITE here because this indicates how - * to treat the socket with which the packet is - * associated. If this packet is associated with a - * socket at all, it must be the originator of the - * packet. Incoming packets will have no socket - * associated with them at this point. - */ - kfree_skb(skb,FREE_WRITE); - } - return retval; -} - -static int -ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy) -{ - ipx_packet *ipx = (ipx_packet *)(skb->h.raw); - ipx_socket *sock1 = NULL, *sock2 = NULL; - struct sk_buff *skb1 = NULL, *skb2 = NULL; - int ipx_offset; - - sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock); - - /* - * We need to check if there is a primary net and if - * this is addressed to one of the *SPECIAL* sockets because - * these need to be propagated to the primary net. - * The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and - * 0x456(Diagnostic). - */ - if (ipx_primary_net && (intrfc != ipx_primary_net)) { - switch (ntohs(ipx->ipx_dest.sock)) { - case 0x452: - case 0x453: - case 0x456: - /* - * The appropriate thing to do here is to - * dup the packet and route to the primary net - * interface via ipxitf_send; however, we'll cheat - * and just demux it here. - */ - sock2 = ipxitf_find_socket(ipx_primary_net, - ipx->ipx_dest.sock); - break; - default: - break; - } - } - - /* if there is nothing to do, return */ - if ((sock1 == NULL) && (sock2 == NULL)) { - if (!copy) - kfree_skb(skb,FREE_WRITE); - return 0; - } - - ipx_offset = (char *)(skb->h.raw) - (char *)(skb->data); - - /* This next segment of code is a little awkward, but it sets it up - * so that the appropriate number of copies of the SKB are made and - * that skb1 and skb2 point to it (them) so that it (they) can be - * demuxed to sock1 and/or sock2. If we are unable to make enough - * copies, we do as much as is possible. - */ - if (copy) { - skb1 = skb_clone(skb, GFP_ATOMIC); - if (skb1 != NULL) { - skb1->h.raw = (unsigned char *)&(skb1->data[ipx_offset]); - skb1->arp = skb1->free = 1; - } - } else { - skb1 = skb; - } - - if (skb1 == NULL) return -ENOMEM; - - /* Do we need 2 SKBs? */ - if (sock1 && sock2) { - skb2 = skb_clone(skb1, GFP_ATOMIC); - if (skb2 != NULL) { - skb2->h.raw = (unsigned char *)&(skb2->data[ipx_offset]); - skb2->arp = skb2->free = 1; - } - } else { - skb2 = skb1; - } - - if (sock1) { - (void) ipxitf_def_skb_handler(sock1, skb1); - } - - if (skb2 == NULL) return -ENOMEM; - - if (sock2) { - (void) ipxitf_def_skb_handler(sock2, skb2); - } - - return 0; -} - -static struct sk_buff * -ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buff *skb) -{ - struct sk_buff *skb2; - int in_offset = skb->h.raw - skb->data; - int out_offset = intrfc->if_ipx_offset; - char *oldraw; - int len; - - /* Hopefully, most cases */ - if (in_offset == out_offset) { - skb->len += out_offset; - skb->arp = skb->free = 1; - return skb; - } - - /* Existing SKB will work, just need to move things around a little */ - if (in_offset > out_offset) { - oldraw = skb->h.raw; - skb->h.raw = &(skb->data[out_offset]); - memmove(skb->h.raw, oldraw, skb->len); - skb->len += out_offset; - skb->arp = skb->free = 1; - return skb; - } - - /* Need new SKB */ - len = skb->len + out_offset; - skb2 = alloc_skb(len, GFP_ATOMIC); - if (skb2 != NULL) { - skb2->h.raw = &(skb2->data[out_offset]); - skb2->len = len; - skb2->free=1; - skb2->arp=1; - memcpy(skb2->h.raw, skb->h.raw, skb->len); - } - kfree_skb(skb, FREE_WRITE); - return skb2; -} - -static int -ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node) -{ - ipx_packet *ipx = (ipx_packet *)(skb->h.raw); - struct device *dev = intrfc->if_dev; - struct datalink_proto *dl = intrfc->if_dlink; - char dest_node[IPX_NODE_LEN]; - int send_to_wire = 1; - int addr_len; - - /* We need to know how many skbuffs it will take to send out this - * packet to avoid unnecessary copies. - */ - if ((dl == NULL) || (dev == NULL) || (dev->flags & IFF_LOOPBACK)) - send_to_wire = 0; - - /* See if this should be demuxed to sockets on this interface */ - if (ipx->ipx_dest.net == intrfc->if_netnum) { - if (memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0) - return ipxitf_demux_socket(intrfc, skb, 0); - if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) { - ipxitf_demux_socket(intrfc, skb, send_to_wire); - if (!send_to_wire) return 0; - } - } - - /* if the originating net is not equal to our net; this is routed */ - if (ipx->ipx_source.net != intrfc->if_netnum) { - if (++(ipx->ipx_tctrl) > ipxcfg_max_hops) - send_to_wire = 0; - } - - if (!send_to_wire) { - /* - * We do a FREE_WRITE here because this indicates how - * to treat the socket with which the packet is - * associated. If this packet is associated with a - * socket at all, it must be the originator of the - * packet. Routed packets will have no socket associated - * with them. - */ - kfree_skb(skb,FREE_WRITE); - return 0; - } - - /* determine the appropriate hardware address */ - addr_len = dev->addr_len; - if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) { - memcpy(dest_node, dev->broadcast, addr_len); - } else { - memcpy(dest_node, &(node[IPX_NODE_LEN-addr_len]), addr_len); - } - - /* make any compensation for differing physical/data link size */ - skb = ipxitf_adjust_skbuff(intrfc, skb); - if (skb == NULL) return 0; - - /* set up data link and physical headers */ - skb->dev = dev; - dl->datalink_header(dl, skb, dest_node); - - if (skb->sk != NULL) { - /* This is an outbound packet from this host. We need to - * increment the write count. - */ - skb->sk->wmem_alloc += skb->mem_len; - } - - /* Send it out */ - dev_queue_xmit(skb, dev, SOPRI_NORMAL); - return 0; -} - -static int -ipxrtr_add_route(unsigned long, ipx_interface *, unsigned char *); - -static int -ipxitf_add_local_route(ipx_interface *intrfc) -{ - return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL); -} - -static char * ipx_frame_name(unsigned short); -static char * ipx_device_name(ipx_interface *); -static int ipxrtr_route_skb(struct sk_buff *); - -static int -ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb) -{ - ipx_packet *ipx = (ipx_packet *) (skb->h.raw); - ipx_interface *i; - - /* See if we should update our network number */ - if ((intrfc->if_netnum == 0L) && - (ipx->ipx_source.net == ipx->ipx_dest.net) && - (ipx->ipx_source.net != 0L)) { - /* NB: NetWare servers lie about their hop count so we - * dropped the test based on it. This is the best way - * to determine this is a 0 hop count packet. - */ - if ((i=ipxitf_find_using_net(ipx->ipx_source.net))==NULL) { - intrfc->if_netnum = ipx->ipx_source.net; - (void) ipxitf_add_local_route(intrfc); - } else { - printk("IPX: Network number collision %lx\n\t%s %s and %s %s\n", - htonl(ipx->ipx_source.net), - ipx_device_name(i), - ipx_frame_name(i->if_dlink_type), - ipx_device_name(intrfc), - ipx_frame_name(intrfc->if_dlink_type)); - } - } - - if (ipx->ipx_dest.net == 0L) - ipx->ipx_dest.net = intrfc->if_netnum; - if (ipx->ipx_source.net == 0L) - ipx->ipx_source.net = intrfc->if_netnum; - - if (intrfc->if_netnum != ipx->ipx_dest.net) { - /* We only route point-to-point packets. */ - if ((skb->pkt_type != PACKET_BROADCAST) && - (skb->pkt_type != PACKET_MULTICAST)) - return ipxrtr_route_skb(skb); - - kfree_skb(skb,FREE_READ); - return 0; - } - - /* see if we should keep it */ - if ((memcmp(ipx_broadcast_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0) - || (memcmp(intrfc->if_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0)) { - return ipxitf_demux_socket(intrfc, skb, 0); - } - - /* we couldn't pawn it off so unload it */ - kfree_skb(skb,FREE_READ); - return 0; -} - -static void -ipxitf_insert(ipx_interface *intrfc) -{ - ipx_interface *i; - - intrfc->if_next = NULL; - if (ipx_interfaces == NULL) { - ipx_interfaces = intrfc; - } else { - for (i = ipx_interfaces; i->if_next != NULL; i = i->if_next) - ; - i->if_next = intrfc; - } - - if (ipxcfg_auto_select_primary && (ipx_primary_net == NULL)) - ipx_primary_net = intrfc; -} - -static int -ipxitf_create_internal(ipx_interface_definition *idef) -{ - ipx_interface *intrfc; - - /* Only one primary network allowed */ - if (ipx_primary_net != NULL) return -EEXIST; - - /* Must have a valid network number */ - if (idef->ipx_network == 0L) return -EADDRNOTAVAIL; - if (ipxitf_find_using_net(idef->ipx_network) != NULL) - return -EADDRINUSE; - - intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC); - if (intrfc==NULL) - return -EAGAIN; - intrfc->if_dev=NULL; - intrfc->if_netnum=idef->ipx_network; - intrfc->if_dlink_type = 0; - intrfc->if_dlink = NULL; - intrfc->if_sklist = NULL; - intrfc->if_internal = 1; - intrfc->if_ipx_offset = 0; - intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; - memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN); - ipx_internal_net = intrfc; - ipx_primary_net = intrfc; - ipxitf_insert(intrfc); - return ipxitf_add_local_route(intrfc); -} - -static int -ipx_map_frame_type(unsigned char type) -{ - switch (type) { - case IPX_FRAME_ETHERII: return htons(ETH_P_IPX); - case IPX_FRAME_8022: return htons(ETH_P_802_2); - case IPX_FRAME_SNAP: return htons(ETH_P_SNAP); - case IPX_FRAME_8023: return htons(ETH_P_802_3); - } - return 0; -} - -static int -ipxitf_create(ipx_interface_definition *idef) -{ - struct device *dev; - unsigned short dlink_type = 0; - struct datalink_proto *datalink = NULL; - ipx_interface *intrfc; - - if (idef->ipx_special == IPX_INTERNAL) - return ipxitf_create_internal(idef); - - if ((idef->ipx_special == IPX_PRIMARY) && (ipx_primary_net != NULL)) - return -EEXIST; - - if ((idef->ipx_network != 0L) && - (ipxitf_find_using_net(idef->ipx_network) != NULL)) - return -EADDRINUSE; - - switch (idef->ipx_dlink_type) { - case IPX_FRAME_ETHERII: - dlink_type = htons(ETH_P_IPX); - datalink = pEII_datalink; - break; - case IPX_FRAME_8022: - dlink_type = htons(ETH_P_802_2); - datalink = p8022_datalink; - break; - case IPX_FRAME_SNAP: - dlink_type = htons(ETH_P_SNAP); - datalink = pSNAP_datalink; - break; - case IPX_FRAME_8023: - dlink_type = htons(ETH_P_802_3); - datalink = p8023_datalink; - break; - case IPX_FRAME_NONE: - default: - break; - } - - if (datalink == NULL) - return -EPROTONOSUPPORT; - - dev=dev_get(idef->ipx_device); - if (dev==NULL) - return -ENODEV; - - if (!(dev->flags & IFF_UP)) - return -ENETDOWN; - - /* Check addresses are suitable */ - if(dev->addr_len>IPX_NODE_LEN) - return -EINVAL; - - if ((intrfc = ipxitf_find_using_phys(dev, dlink_type)) == NULL) { - - /* Ok now create */ - intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC); - if (intrfc==NULL) - return -EAGAIN; - intrfc->if_dev=dev; - intrfc->if_netnum=idef->ipx_network; - intrfc->if_dlink_type = dlink_type; - intrfc->if_dlink = datalink; - intrfc->if_sklist = NULL; - intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; - /* Setup primary if necessary */ - if ((idef->ipx_special == IPX_PRIMARY)) - ipx_primary_net = intrfc; - intrfc->if_internal = 0; - intrfc->if_ipx_offset = dev->hard_header_len + datalink->header_length; - memset(intrfc->if_node, 0, IPX_NODE_LEN); - memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]), dev->dev_addr, dev->addr_len); - - ipxitf_insert(intrfc); - } - - /* If the network number is known, add a route */ - if (intrfc->if_netnum == 0L) - return 0; - - return ipxitf_add_local_route(intrfc); -} - -static int -ipxitf_delete(ipx_interface_definition *idef) -{ - struct device *dev = NULL; - unsigned short dlink_type = 0; - ipx_interface *intrfc; - - if (idef->ipx_special == IPX_INTERNAL) { - if (ipx_internal_net != NULL) { - ipxitf_down(ipx_internal_net); - return 0; - } - return -ENOENT; - } - - dlink_type = ipx_map_frame_type(idef->ipx_dlink_type); - if (dlink_type == 0) - return -EPROTONOSUPPORT; - - dev=dev_get(idef->ipx_device); - if(dev==NULL) return -ENODEV; - - intrfc = ipxitf_find_using_phys(dev, dlink_type); - if (intrfc != NULL) { - ipxitf_down(intrfc); - return 0; - } - return -EINVAL; -} - -static ipx_interface * -ipxitf_auto_create(struct device *dev, unsigned short dlink_type) -{ - struct datalink_proto *datalink = NULL; - ipx_interface *intrfc; - - switch (htons(dlink_type)) { - case ETH_P_IPX: datalink = pEII_datalink; break; - case ETH_P_802_2: datalink = p8022_datalink; break; - case ETH_P_SNAP: datalink = pSNAP_datalink; break; - case ETH_P_802_3: datalink = p8023_datalink; break; - default: return NULL; - } - - if (dev == NULL) - return NULL; - - /* Check addresses are suitable */ - if(dev->addr_len>IPX_NODE_LEN) return NULL; - - intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC); - if (intrfc!=NULL) { - intrfc->if_dev=dev; - intrfc->if_netnum=0L; - intrfc->if_dlink_type = dlink_type; - intrfc->if_dlink = datalink; - intrfc->if_sklist = NULL; - intrfc->if_internal = 0; - intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; - intrfc->if_ipx_offset = dev->hard_header_len + - datalink->header_length; - memset(intrfc->if_node, 0, IPX_NODE_LEN); - memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]), - dev->dev_addr, dev->addr_len); - ipxitf_insert(intrfc); - } - - return intrfc; -} - -static int -ipxitf_ioctl(unsigned int cmd, void *arg) -{ - int err; - switch(cmd) - { - case SIOCSIFADDR: - { - struct ifreq ifr; - struct sockaddr_ipx *sipx; - ipx_interface_definition f; - err=verify_area(VERIFY_READ,arg,sizeof(ifr)); - if(err) - return err; - memcpy_fromfs(&ifr,arg,sizeof(ifr)); - sipx=(struct sockaddr_ipx *)&ifr.ifr_addr; - if(sipx->sipx_family!=AF_IPX) - return -EINVAL; - f.ipx_network=sipx->sipx_network; - memcpy(f.ipx_device, ifr.ifr_name, sizeof(f.ipx_device)); - memcpy(f.ipx_node, sipx->sipx_node, IPX_NODE_LEN); - f.ipx_dlink_type=sipx->sipx_type; - f.ipx_special=sipx->sipx_special; - if(sipx->sipx_action==IPX_DLTITF) - return ipxitf_delete(&f); - else - return ipxitf_create(&f); - } - case SIOCGIFADDR: - { - struct ifreq ifr; - struct sockaddr_ipx *sipx; - ipx_interface *ipxif; - struct device *dev; - err=verify_area(VERIFY_WRITE,arg,sizeof(ifr)); - if(err) - return err; - memcpy_fromfs(&ifr,arg,sizeof(ifr)); - sipx=(struct sockaddr_ipx *)&ifr.ifr_addr; - dev=dev_get(ifr.ifr_name); - if(!dev) - return -ENODEV; - ipxif=ipxitf_find_using_phys(dev, ipx_map_frame_type(sipx->sipx_type)); - if(ipxif==NULL) - return -EADDRNOTAVAIL; - sipx->sipx_network=ipxif->if_netnum; - memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node)); - memcpy_tofs(arg,&ifr,sizeof(ifr)); - return 0; - } - case SIOCAIPXITFCRT: - err=verify_area(VERIFY_READ,arg,sizeof(char)); - if(err) - return err; - return ipxcfg_set_auto_create(get_fs_byte(arg)); - case SIOCAIPXPRISLT: - err=verify_area(VERIFY_READ,arg,sizeof(char)); - if(err) - return err; - return ipxcfg_set_auto_select(get_fs_byte(arg)); - default: - return -EINVAL; - } -} - -/*******************************************************************************************************************\ -* * -* Routing tables for the IPX socket layer * -* * -\*******************************************************************************************************************/ - -static ipx_route * -ipxrtr_lookup(unsigned long net) -{ - ipx_route *r; - - for (r=ipx_routes; (r!=NULL) && (r->ir_net!=net); r=r->ir_next) - ; - - return r; -} - -static int -ipxrtr_add_route(unsigned long network, ipx_interface *intrfc, unsigned char *node) -{ - ipx_route *rt; - - /* Get a route structure; either existing or create */ - rt = ipxrtr_lookup(network); - if (rt==NULL) { - rt=(ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC); - if(rt==NULL) - return -EAGAIN; - rt->ir_next=ipx_routes; - ipx_routes=rt; - } - - rt->ir_net = network; - rt->ir_intrfc = intrfc; - if (node == NULL) { - memset(rt->ir_router_node, '\0', IPX_NODE_LEN); - rt->ir_routed = 0; - } else { - memcpy(rt->ir_router_node, node, IPX_NODE_LEN); - rt->ir_routed=1; - } - return 0; -} - -static void -ipxrtr_del_routes(ipx_interface *intrfc) -{ - ipx_route **r, *tmp; - - for (r = &ipx_routes; (tmp = *r) != NULL; ) { - if (tmp->ir_intrfc == intrfc) { - *r = tmp->ir_next; - kfree_s(tmp, sizeof(ipx_route)); - } else { - r = &(tmp->ir_next); - } - } -} - -static int -ipxrtr_create(ipx_route_definition *rd) -{ - ipx_interface *intrfc; - - /* Find the appropriate interface */ - intrfc = ipxitf_find_using_net(rd->ipx_router_network); - if (intrfc == NULL) - return -ENETUNREACH; - - return ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node); -} - - -static int -ipxrtr_delete(long net) -{ - ipx_route **r; - ipx_route *tmp; - - for (r = &ipx_routes; (tmp = *r) != NULL; ) { - if (tmp->ir_net == net) { - if (!(tmp->ir_routed)) { - /* Directly connected; can't lose route */ - return -EPERM; - } - *r = tmp->ir_next; - kfree_s(tmp, sizeof(ipx_route)); - return 0; - } - r = &(tmp->ir_next); - } - - return -ENOENT; -} - -static int -ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, void *ubuf, int len) -{ - struct sk_buff *skb; - ipx_interface *intrfc; - ipx_packet *ipx; - int size; - int ipx_offset; - ipx_route *rt = NULL; - - /* Find the appropriate interface on which to send packet */ - if ((usipx->sipx_network == 0L) && (ipx_primary_net != NULL)) { - usipx->sipx_network = ipx_primary_net->if_netnum; - intrfc = ipx_primary_net; - } else { - rt = ipxrtr_lookup(usipx->sipx_network); - if (rt==NULL) { - return -ENETUNREACH; - } - intrfc = rt->ir_intrfc; - } - - ipx_offset = intrfc->if_ipx_offset; - size=sizeof(ipx_packet)+len; - size += ipx_offset; - - if(size+sk->wmem_alloc>sk->sndbuf) return -EAGAIN; - - skb=alloc_skb(size,GFP_KERNEL); - if(skb==NULL) return -ENOMEM; - - skb->sk=sk; - skb->len=size; - skb->free=1; - skb->arp=1; - - /* Fill in IPX header */ - ipx=(ipx_packet *)&(skb->data[ipx_offset]); - ipx->ipx_checksum=0xFFFF; - ipx->ipx_pktsize=htons(len+sizeof(ipx_packet)); - ipx->ipx_tctrl=0; - ipx->ipx_type=usipx->sipx_type; - skb->h.raw = (unsigned char *)ipx; - - ipx->ipx_source.net = sk->ipx_intrfc->if_netnum; - memcpy(ipx->ipx_source.node, sk->ipx_intrfc->if_node, IPX_NODE_LEN); - ipx->ipx_source.sock = sk->ipx_port; - ipx->ipx_dest.net=usipx->sipx_network; - memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN); - ipx->ipx_dest.sock=usipx->sipx_port; - - memcpy_fromfs((char *)(ipx+1),ubuf,len); - return ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? - rt->ir_router_node : ipx->ipx_dest.node); -} - -static int -ipxrtr_route_skb(struct sk_buff *skb) -{ - ipx_packet *ipx = (ipx_packet *) (skb->h.raw); - ipx_route *r; - ipx_interface *i; - - r = ipxrtr_lookup(ipx->ipx_dest.net); - if (r == NULL) { - /* no known route */ - kfree_skb(skb,FREE_READ); - return 0; - } - i = r->ir_intrfc; - (void)ipxitf_send(i, skb, (r->ir_routed) ? - r->ir_router_node : ipx->ipx_dest.node); - return 0; -} - -/* - * We use a normal struct rtentry for route handling - */ - -static int ipxrtr_ioctl(unsigned int cmd, void *arg) -{ - int err; - struct rtentry rt; /* Use these to behave like 'other' stacks */ - struct sockaddr_ipx *sg,*st; - - err=verify_area(VERIFY_READ,arg,sizeof(rt)); - if(err) - return err; - - memcpy_fromfs(&rt,arg,sizeof(rt)); - - sg=(struct sockaddr_ipx *)&rt.rt_gateway; - st=(struct sockaddr_ipx *)&rt.rt_dst; - - if(!(rt.rt_flags&RTF_GATEWAY)) - return -EINVAL; /* Direct routes are fixed */ - if(sg->sipx_family!=AF_IPX) - return -EINVAL; - if(st->sipx_family!=AF_IPX) - return -EINVAL; - - switch(cmd) - { - case SIOCDELRT: - return ipxrtr_delete(st->sipx_network); - case SIOCADDRT: - { - struct ipx_route_definition f; - f.ipx_network=st->sipx_network; - f.ipx_router_network=sg->sipx_network; - memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN); - return ipxrtr_create(&f); - } - default: - return -EINVAL; - } -} - -static char * -ipx_frame_name(unsigned short frame) -{ - switch (ntohs(frame)) { - case ETH_P_IPX: return "EtherII"; - case ETH_P_802_2: return "802.2"; - case ETH_P_SNAP: return "SNAP"; - case ETH_P_802_3: return "802.3"; - default: return "None"; - } -} - -static char * -ipx_device_name(ipx_interface *intrfc) -{ - return (intrfc->if_internal ? "Internal" : - (intrfc->if_dev ? intrfc->if_dev->name : "Unknown")); -} - -/* Called from proc fs */ -int -ipx_get_interface_info(char *buffer, char **start, off_t offset, int length) -{ - ipx_interface *i; - int len=0; - off_t pos=0; - off_t begin=0; - - /* Theory.. Keep printing in the same place until we pass offset */ - - len += sprintf (buffer,"%-11s%-15s%-9s%-11s%s\n", "Network", - "Node_Address", "Primary", "Device", "Frame_Type"); - for (i = ipx_interfaces; i != NULL; i = i->if_next) { - len += sprintf(buffer+len, "%08lX ", ntohl(i->if_netnum)); - len += sprintf (buffer+len,"%02X%02X%02X%02X%02X%02X ", - i->if_node[0], i->if_node[1], i->if_node[2], - i->if_node[3], i->if_node[4], i->if_node[5]); - len += sprintf(buffer+len, "%-9s", (i == ipx_primary_net) ? - "Yes" : "No"); - len += sprintf (buffer+len, "%-11s", ipx_device_name(i)); - len += sprintf (buffer+len, "%s\n", - ipx_frame_name(i->if_dlink_type)); - - /* Are we still dumping unwanted data then discard the record */ - pos=begin+len; - - if(posoffset+length) /* We have dumped enough */ - break; - } - - /* The data in question runs from begin to begin+len */ - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Remove unwanted header data from length */ - if(len>length) - len=length; /* Remove unwanted tail data from length */ - - return len; -} - -int -ipx_get_info(char *buffer, char **start, off_t offset, int length) -{ - ipx_socket *s; - ipx_interface *i; - int len=0; - off_t pos=0; - off_t begin=0; - - /* Theory.. Keep printing in the same place until we pass offset */ - - len += sprintf (buffer,"%-15s%-28s%-10s%-10s%-7s%s\n", "Local_Address", - "Remote_Address", "Tx_Queue", "Rx_Queue", - "State", "Uid"); - for (i = ipx_interfaces; i != NULL; i = i->if_next) { - for (s = i->if_sklist; s != NULL; s = s->next) { - len += sprintf (buffer+len,"%08lX:%04X ", - htonl(i->if_netnum), - htons(s->ipx_port)); - if (s->state!=TCP_ESTABLISHED) { - len += sprintf(buffer+len, "%-28s", "Not_Connected"); - } else { - len += sprintf (buffer+len, - "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", - htonl(s->ipx_dest_addr.net), - s->ipx_dest_addr.node[0], s->ipx_dest_addr.node[1], - s->ipx_dest_addr.node[2], s->ipx_dest_addr.node[3], - s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5], - htons(s->ipx_dest_addr.sock)); - } - len += sprintf (buffer+len,"%08lX %08lX ", - s->wmem_alloc, s->rmem_alloc); - len += sprintf (buffer+len,"%02X %03d\n", - s->state, SOCK_INODE(s->socket)->i_uid); - - /* Are we still dumping unwanted data then discard the record */ - pos=begin+len; - - if(posoffset+length) /* We have dumped enough */ - break; - } - } - - /* The data in question runs from begin to begin+len */ - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Remove unwanted header data from length */ - if(len>length) - len=length; /* Remove unwanted tail data from length */ - - return len; -} - -int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length) -{ - ipx_route *rt; - int len=0; - off_t pos=0; - off_t begin=0; - - len += sprintf (buffer,"%-11s%-13s%s\n", - "Network", "Router_Net", "Router_Node"); - for (rt = ipx_routes; rt != NULL; rt = rt->ir_next) - { - len += sprintf (buffer+len,"%08lX ", ntohl(rt->ir_net)); - if (rt->ir_routed) { - len += sprintf (buffer+len,"%08lX %02X%02X%02X%02X%02X%02X\n", - ntohl(rt->ir_intrfc->if_netnum), - rt->ir_router_node[0], rt->ir_router_node[1], - rt->ir_router_node[2], rt->ir_router_node[3], - rt->ir_router_node[4], rt->ir_router_node[5]); - } else { - len += sprintf (buffer+len, "%-13s%s\n", - "Directly", "Connected"); - } - pos=begin+len; - if(posoffset+length) - break; - } - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - -/*******************************************************************************************************************\ -* * -* Handling for system calls applied via the various interfaces to an IPX socket object * -* * -\*******************************************************************************************************************/ - -static int ipx_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - switch(cmd) - { - default: - return(-EINVAL); - } -} - -static int ipx_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) -{ - ipx_socket *sk; - int err,opt; - - sk=(ipx_socket *)sock->data; - - if(optval==NULL) - return(-EINVAL); - - err=verify_area(VERIFY_READ,optval,sizeof(int)); - if(err) - return err; - opt=get_fs_long((unsigned long *)optval); - - switch(level) - { - case SOL_IPX: - switch(optname) - { - case IPX_TYPE: - sk->ipx_type=opt; - return 0; - default: - return -EOPNOTSUPP; - } - break; - - case SOL_SOCKET: - return sock_setsockopt(sk,level,optname,optval,optlen); - - default: - return -EOPNOTSUPP; - } -} - -static int ipx_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) -{ - ipx_socket *sk; - int val=0; - int err; - - sk=(ipx_socket *)sock->data; - - switch(level) - { - - case SOL_IPX: - switch(optname) - { - case IPX_TYPE: - val=sk->ipx_type; - break; - default: - return -ENOPROTOOPT; - } - break; - - case SOL_SOCKET: - return sock_getsockopt(sk,level,optname,optval,optlen); - - default: - return -EOPNOTSUPP; - } - err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); - if(err) - return err; - put_fs_long(sizeof(int),(unsigned long *)optlen); - err=verify_area(VERIFY_WRITE,optval,sizeof(int)); - put_fs_long(val,(unsigned long *)optval); - return(0); -} - -static int ipx_listen(struct socket *sock, int backlog) -{ - return -EOPNOTSUPP; -} - -static void def_callback1(struct sock *sk) -{ - if(!sk->dead) - wake_up_interruptible(sk->sleep); -} - -static void def_callback2(struct sock *sk, int len) -{ - if(!sk->dead) - { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 1); - } -} - -static int -ipx_create(struct socket *sock, int protocol) -{ - ipx_socket *sk; - sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL); - if(sk==NULL) - return(-ENOMEM); - switch(sock->type) - { - case SOCK_DGRAM: - break; - default: - kfree_s((void *)sk,sizeof(*sk)); - return(-ESOCKTNOSUPPORT); - } - sk->dead=0; - sk->next=NULL; - sk->broadcast=0; - sk->rcvbuf=SK_RMEM_MAX; - sk->sndbuf=SK_WMEM_MAX; - sk->wmem_alloc=0; - sk->rmem_alloc=0; - sk->inuse=0; - sk->shutdown=0; - sk->prot=NULL; /* So we use default free mechanisms */ - sk->broadcast=0; - sk->err=0; - skb_queue_head_init(&sk->receive_queue); - skb_queue_head_init(&sk->write_queue); - sk->send_head=NULL; - skb_queue_head_init(&sk->back_log); - sk->state=TCP_CLOSE; - sk->socket=sock; - sk->type=sock->type; - sk->ipx_type=0; /* General user level IPX */ - sk->debug=0; - sk->ipx_intrfc = NULL; - memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr)); - sk->ipx_port = 0; - sk->mtu=IPX_MTU; - - if(sock!=NULL) - { - sock->data=(void *)sk; - sk->sleep=sock->wait; - } - - sk->state_change=def_callback1; - sk->data_ready=def_callback2; - sk->write_space=def_callback1; - sk->error_report=def_callback1; - - sk->zapped=1; - return 0; -} - -static int ipx_release(struct socket *sock, struct socket *peer) -{ - ipx_socket *sk=(ipx_socket *)sock->data; - if(sk==NULL) - return(0); - if(!sk->dead) - sk->state_change(sk); - sk->dead=1; - sock->data=NULL; - ipx_destroy_socket(sk); - return(0); -} - -static int ipx_dup(struct socket *newsock,struct socket *oldsock) -{ - return(ipx_create(newsock,SOCK_DGRAM)); -} - -static unsigned short -ipx_first_free_socketnum(ipx_interface *intrfc) -{ - unsigned short socketNum = intrfc->if_sknum; - - if (socketNum < IPX_MIN_EPHEMERAL_SOCKET) - socketNum = IPX_MIN_EPHEMERAL_SOCKET; - - while (ipxitf_find_socket(intrfc, ntohs(socketNum)) != NULL) - if (socketNum > IPX_MAX_EPHEMERAL_SOCKET) - socketNum = IPX_MIN_EPHEMERAL_SOCKET; - else - socketNum++; - - intrfc->if_sknum = socketNum; - return ntohs(socketNum); -} - -static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) -{ - ipx_socket *sk; - ipx_interface *intrfc; - struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr; - - sk=(ipx_socket *)sock->data; - - if(sk->zapped==0) - return -EIO; - - if(addr_len!=sizeof(struct sockaddr_ipx)) - return -EINVAL; - - intrfc = ipxitf_find_using_net(addr->sipx_network); - if (intrfc == NULL) - return -EADDRNOTAVAIL; - - if (addr->sipx_port == 0) { - addr->sipx_port = ipx_first_free_socketnum(intrfc); - if (addr->sipx_port == 0) - return -EINVAL; - } - - if(ntohs(addr->sipx_port)sipx_port)!=NULL) { - if(sk->debug) - printk("IPX: bind failed because port %X in use.\n", - (int)addr->sipx_port); - return -EADDRINUSE; - } - - sk->ipx_port=addr->sipx_port; - ipxitf_insert_socket(intrfc, sk); - sk->zapped=0; - if(sk->debug) - printk("IPX: socket is bound.\n"); - return 0; -} - -static int ipx_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) -{ - ipx_socket *sk=(ipx_socket *)sock->data; - struct sockaddr_ipx *addr; - - sk->state = TCP_CLOSE; - sock->state = SS_UNCONNECTED; - - if(addr_len!=sizeof(*addr)) - return(-EINVAL); - addr=(struct sockaddr_ipx *)uaddr; - - if(sk->ipx_port==0) - /* put the autobinding in */ - { - struct sockaddr_ipx uaddr; - int ret; - - uaddr.sipx_port = 0; - uaddr.sipx_network = 0L; - ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); - if (ret != 0) return (ret); - } - - if(ipxrtr_lookup(addr->sipx_network)==NULL) - return -ENETUNREACH; - sk->ipx_dest_addr.net=addr->sipx_network; - sk->ipx_dest_addr.sock=addr->sipx_port; - memcpy(sk->ipx_dest_addr.node,addr->sipx_node,IPX_NODE_LEN); - sk->ipx_type=addr->sipx_type; - sock->state = SS_CONNECTED; - sk->state=TCP_ESTABLISHED; - return 0; -} - -static int ipx_socketpair(struct socket *sock1, struct socket *sock2) -{ - return(-EOPNOTSUPP); -} - -static int ipx_accept(struct socket *sock, struct socket *newsock, int flags) -{ - if(newsock->data) - kfree_s(newsock->data,sizeof(ipx_socket)); - return -EOPNOTSUPP; -} - -static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) -{ - ipx_address *addr; - struct sockaddr_ipx sipx; - ipx_socket *sk; - - sk=(ipx_socket *)sock->data; - - *uaddr_len = sizeof(struct sockaddr_ipx); - - if(peer) { - if(sk->state!=TCP_ESTABLISHED) - return -ENOTCONN; - addr=&sk->ipx_dest_addr; - sipx.sipx_network = addr->net; - memcpy(sipx.sipx_node,addr->node,IPX_NODE_LEN); - sipx.sipx_port = addr->sock; - } else { - if (sk->ipx_intrfc != NULL) { - sipx.sipx_network = sk->ipx_intrfc->if_netnum; - memcpy(sipx.sipx_node, sk->ipx_intrfc->if_node, - IPX_NODE_LEN); - } else { - sipx.sipx_network = 0L; - memset(sipx.sipx_node, '\0', IPX_NODE_LEN); - } - sipx.sipx_port = sk->ipx_port; - } - - sipx.sipx_family = AF_IPX; - sipx.sipx_type = sk->ipx_type; - memcpy(uaddr,&sipx,sizeof(sipx)); - return 0; -} - -#if 0 -/* - * User to dump IPX packets (debugging) - */ -void dump_data(char *str,unsigned char *d) { - static char h2c[] = "0123456789ABCDEF"; - int l,i; - char *p, b[64]; - for (l=0;l<16;l++) { - p = b; - for (i=0; i < 8 ; i++) { - *(p++) = h2c[d[i] & 0x0f]; - *(p++) = h2c[(d[i] >> 4) & 0x0f]; - *(p++) = ' '; - } - *(p++) = '-'; - *(p++) = ' '; - for (i=0; i < 8 ; i++) *(p++) = ' '<= d[i] && d[i]<'\177' ? d[i] : '.'; - *p = '\000'; - d += i; - printk("%s-%04X: %s\n",str,l*8,b); - } -} - -void dump_addr(char *str,ipx_address *p) { - printk("%s: %08X:%02X%02X%02X%02X%02X%02X:%04X\n", - str,ntohl(p->net),p->node[0],p->node[1],p->node[2], - p->node[3],p->node[4],p->node[5],ntohs(p->sock)); -} - -void dump_hdr(char *str,ipx_packet *p) { - printk("%s: CHKSUM=%04X SIZE=%d (%04X) HOPS=%d (%02X) TYPE=%02X\n", - str,p->ipx_checksum,ntohs(p->ipx_pktsize),ntohs(p->ipx_pktsize), - p->ipx_tctrl,p->ipx_tctrl,p->ipx_type); - dump_addr(" IPX-DST",&p->ipx_dest); - dump_addr(" IPX-SRC",&p->ipx_source); -} - -void dump_pkt(char *str,ipx_packet *p) { - dump_hdr(str,p); - dump_data(str,(unsigned char *)p); -} -#endif - -int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ - /* NULL here for pt means the packet was looped back */ - ipx_interface *intrfc; - ipx_packet *ipx; - - ipx=(ipx_packet *)skb->h.raw; - - if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) { - /* We don't do checksum options. We can't really. Novell don't seem to have documented them. - If you need them try the XNS checksum since IPX is basically XNS in disguise. It might be - the same... */ - kfree_skb(skb,FREE_READ); - return 0; - } - - /* Too small */ - if(htons(ipx->ipx_pktsize)type); - if (intrfc == NULL) { - if (ipxcfg_auto_create_interfaces) { - intrfc = ipxitf_auto_create(dev, pt->type); - } - - if (intrfc == NULL) { - /* Not one of ours */ - kfree_skb(skb,FREE_READ); - return 0; - } - } - - return ipxitf_rcv(intrfc, skb); -} - -static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock, - unsigned flags, struct sockaddr *usip, int addr_len) -{ - ipx_socket *sk=(ipx_socket *)sock->data; - struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip; - struct sockaddr_ipx local_sipx; - int retval; - - if (sk->zapped) return -EIO; /* Socket not bound */ - if(flags) return -EINVAL; - - if(usipx) { - if(sk->ipx_port == 0) { - struct sockaddr_ipx uaddr; - int ret; - - uaddr.sipx_port = 0; - uaddr.sipx_network = 0L; - ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); - if (ret != 0) return ret; - } - - if(addr_len sipx_family != AF_IPX) - return -EINVAL; - } else { - if(sk->state!=TCP_ESTABLISHED) - return -ENOTCONN; - usipx=&local_sipx; - usipx->sipx_family=AF_IPX; - usipx->sipx_type=sk->ipx_type; - usipx->sipx_port=sk->ipx_dest_addr.sock; - usipx->sipx_network=sk->ipx_dest_addr.net; - memcpy(usipx->sipx_node,sk->ipx_dest_addr.node,IPX_NODE_LEN); - } - - retval = ipxrtr_route_packet(sk, usipx, ubuf, len); - if (retval < 0) return retval; - - return len; -} - -static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags) -{ - return ipx_sendto(sock,ubuf,size,noblock,flags,NULL,0); -} - -static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sip, int *addr_len) -{ - ipx_socket *sk=(ipx_socket *)sock->data; - struct sockaddr_ipx *sipx=(struct sockaddr_ipx *)sip; - struct ipx_packet *ipx = NULL; - int copied = 0; - int truesize; - struct sk_buff *skb; - int er; - - if(sk->err) - { - er= -sk->err; - sk->err=0; - return er; - } - - if (sk->zapped) - return -EIO; - - if(addr_len) - *addr_len=sizeof(*sipx); - - skb=skb_recv_datagram(sk,flags,noblock,&er); - if(skb==NULL) - return er; - - ipx = (ipx_packet *)(skb->h.raw); - truesize=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet); - copied = (truesize > size) ? size : truesize; - skb_copy_datagram(skb,sizeof(struct ipx_packet),ubuf,copied); - - if(sipx) - { - sipx->sipx_family=AF_IPX; - sipx->sipx_port=ipx->ipx_source.sock; - memcpy(sipx->sipx_node,ipx->ipx_source.node,IPX_NODE_LEN); - sipx->sipx_network=ipx->ipx_source.net; - sipx->sipx_type = ipx->ipx_type; - } - skb_free_datagram(skb); - return(truesize); -} - -static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock) -{ - return ipx_send(sock,ubuf,size,noblock,0); -} - - -static int ipx_recv(struct socket *sock, void *ubuf, int size , int noblock, - unsigned flags) -{ - ipx_socket *sk=(ipx_socket *)sock->data; - if(sk->zapped) - return -ENOTCONN; - return ipx_recvfrom(sock,ubuf,size,noblock,flags,NULL, NULL); -} - -static int ipx_read(struct socket *sock, char *ubuf, int size, int noblock) -{ - return ipx_recv(sock,ubuf,size,noblock,0); -} - - -static int ipx_shutdown(struct socket *sk,int how) -{ - return -EOPNOTSUPP; -} - -static int ipx_select(struct socket *sock , int sel_type, select_table *wait) -{ - ipx_socket *sk=(ipx_socket *)sock->data; - - return datagram_select(sk,sel_type,wait); -} - -static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) -{ - int err; - long amount=0; - ipx_socket *sk=(ipx_socket *)sock->data; - - switch(cmd) - { - case TIOCOUTQ: - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long)); - if(err) - return err; - amount=sk->sndbuf-sk->wmem_alloc; - if(amount<0) - amount=0; - put_fs_long(amount,(unsigned long *)arg); - return 0; - case TIOCINQ: - { - struct sk_buff *skb; - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if((skb=skb_peek(&sk->receive_queue))!=NULL) - amount=skb->len; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long)); - put_fs_long(amount,(unsigned long *)arg); - return 0; - } - case SIOCADDRT: - case SIOCDELRT: - if(!suser()) - return -EPERM; - return(ipxrtr_ioctl(cmd,(void *)arg)); - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCAIPXITFCRT: - case SIOCAIPXPRISLT: - if(!suser()) - return -EPERM; - return(ipxitf_ioctl(cmd,(void *)arg)); - case SIOCIPXCFGDATA: - { - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(ipx_config_data)); - if(err) return err; - return(ipxcfg_get_config_data((void *)arg)); - } - case SIOCGSTAMP: - if (sk) - { - if(sk->stamp.tv_sec==0) - return -ENOENT; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); - if(err) - return err; - memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval)); - return 0; - } - return -EINVAL; - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - return -EINVAL; - default: - return(dev_ioctl(cmd,(void *) arg)); - } - /*NOTREACHED*/ - return(0); -} - -static struct proto_ops ipx_proto_ops = { - AF_IPX, - - ipx_create, - ipx_dup, - ipx_release, - ipx_bind, - ipx_connect, - ipx_socketpair, - ipx_accept, - ipx_getname, - ipx_read, - ipx_write, - ipx_select, - ipx_ioctl, - ipx_listen, - ipx_send, - ipx_recv, - ipx_sendto, - ipx_recvfrom, - ipx_shutdown, - ipx_setsockopt, - ipx_getsockopt, - ipx_fcntl, -}; - -/* Called by ddi.c on kernel start up */ - -static struct packet_type ipx_8023_packet_type = - -{ - 0, /* MUTTER ntohs(ETH_P_8023),*/ - NULL, /* All devices */ - ipx_rcv, - NULL, - NULL, -}; - -static struct packet_type ipx_dix_packet_type = -{ - 0, /* MUTTER ntohs(ETH_P_IPX),*/ - NULL, /* All devices */ - ipx_rcv, - NULL, - NULL, -}; - -static struct notifier_block ipx_dev_notifier={ - ipxitf_device_event, - NULL, - 0 -}; - - -extern struct datalink_proto *make_EII_client(void); -extern struct datalink_proto *make_8023_client(void); - -void ipx_proto_init(struct net_proto *pro) -{ - unsigned char val = 0xE0; - unsigned char snapval[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 }; - - (void) sock_register(ipx_proto_ops.family, &ipx_proto_ops); - - pEII_datalink = make_EII_client(); - ipx_dix_packet_type.type=htons(ETH_P_IPX); - dev_add_pack(&ipx_dix_packet_type); - - p8023_datalink = make_8023_client(); - ipx_8023_packet_type.type=htons(ETH_P_802_3); - dev_add_pack(&ipx_8023_packet_type); - - if ((p8022_datalink = register_8022_client(val, ipx_rcv)) == NULL) - printk("IPX: Unable to register with 802.2\n"); - - if ((pSNAP_datalink = register_snap_client(snapval, ipx_rcv)) == NULL) - printk("IPX: Unable to register with SNAP\n"); - - register_netdevice_notifier(&ipx_dev_notifier); - - printk("Swansea University Computer Society IPX 0.29 BETA for NET3.019\n"); - printk("IPX Portions Copyright (c) 1995 Caldera, Inc.\n"); -} -#endif diff --git a/pfinet/linux-inet/ipx.h b/pfinet/linux-inet/ipx.h deleted file mode 100644 index 6842c832..00000000 --- a/pfinet/linux-inet/ipx.h +++ /dev/null @@ -1,84 +0,0 @@ - -/* - * The following information is in its entirety obtained from: - * - * Novell 'IPX Router Specification' Version 1.10 - * Part No. 107-000029-001 - * - * Which is available from ftp.novell.com - */ - -#ifndef _NET_INET_IPX_H_ -#define _NET_INET_IPX_H_ - -#include -#include "datalink.h" -#include - -typedef struct -{ - unsigned long net; - unsigned char node[IPX_NODE_LEN]; - unsigned short sock; -} ipx_address; - -#define ipx_broadcast_node "\377\377\377\377\377\377" - -typedef struct ipx_packet -{ - unsigned short ipx_checksum; -#define IPX_NO_CHECKSUM 0xFFFF - unsigned short ipx_pktsize; - unsigned char ipx_tctrl; - unsigned char ipx_type; -#define IPX_TYPE_UNKNOWN 0x00 -#define IPX_TYPE_RIP 0x01 /* may also be 0 */ -#define IPX_TYPE_SAP 0x04 /* may also be 0 */ -#define IPX_TYPE_SPX 0x05 /* Not yet implemented */ -#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */ -#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */ - ipx_address ipx_dest __attribute__ ((packed)); - ipx_address ipx_source __attribute__ ((packed)); -} ipx_packet; - - -typedef struct sock ipx_socket; - -#include "ipxcall.h" -extern int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt); -extern void ipxrtr_device_down(struct device *dev); - -typedef struct ipx_interface { - /* IPX address */ - unsigned long if_netnum; - unsigned char if_node[IPX_NODE_LEN]; - - /* physical device info */ - struct device *if_dev; - struct datalink_proto *if_dlink; - unsigned short if_dlink_type; - - /* socket support */ - unsigned short if_sknum; - ipx_socket *if_sklist; - - /* administrative overhead */ - int if_ipx_offset; - unsigned char if_internal; - unsigned char if_primary; - - struct ipx_interface *if_next; -} ipx_interface; - -typedef struct ipx_route { - unsigned long ir_net; - ipx_interface *ir_intrfc; - unsigned char ir_routed; - unsigned char ir_router_node[IPX_NODE_LEN]; - struct ipx_route *ir_next; -} ipx_route; - -#define IPX_MIN_EPHEMERAL_SOCKET 0x4000 -#define IPX_MAX_EPHEMERAL_SOCKET 0x7fff - -#endif diff --git a/pfinet/linux-inet/ipxcall.h b/pfinet/linux-inet/ipxcall.h deleted file mode 100644 index eb5bd2bd..00000000 --- a/pfinet/linux-inet/ipxcall.h +++ /dev/null @@ -1,2 +0,0 @@ -/* Separate to keep compilation of protocols.c simpler */ -extern void ipx_proto_init(struct net_proto *pro); diff --git a/pfinet/linux-inet/p8022.c b/pfinet/linux-inet/p8022.c deleted file mode 100644 index 8ff3ec60..00000000 --- a/pfinet/linux-inet/p8022.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include -#include "datalink.h" -#include -#include - -static struct datalink_proto *p8022_list = NULL; - -static struct datalink_proto * -find_8022_client(unsigned char type) -{ - struct datalink_proto *proto; - - for (proto = p8022_list; - ((proto != NULL) && (*(proto->type) != type)); - proto = proto->next) - ; - - return proto; -} - -int -p8022_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ - struct datalink_proto *proto; - - proto = find_8022_client(*(skb->h.raw)); - if (proto != NULL) { - skb->h.raw += 3; - skb->len -= 3; - return proto->rcvfunc(skb, dev, pt); - } - - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return 0; -} - -static void -p8022_datalink_header(struct datalink_proto *dl, - struct sk_buff *skb, unsigned char *dest_node) -{ - struct device *dev = skb->dev; - unsigned long len = skb->len; - unsigned long hard_len = dev->hard_header_len; - unsigned char *rawp; - - dev->hard_header(skb->data, dev, len - hard_len, - dest_node, NULL, len - hard_len, skb); - rawp = skb->data + hard_len; - *rawp = dl->type[0]; - rawp++; - *rawp = dl->type[0]; - rawp++; - *rawp = 0x03; /* UI */ - rawp++; - skb->h.raw = rawp; -} - -static struct packet_type p8022_packet_type = -{ - 0, /* MUTTER ntohs(ETH_P_IPX),*/ - NULL, /* All devices */ - p8022_rcv, - NULL, - NULL, -}; - - -void p8022_proto_init(struct net_proto *pro) -{ - p8022_packet_type.type=htons(ETH_P_802_2); - dev_add_pack(&p8022_packet_type); -} - -struct datalink_proto * -register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)) -{ - struct datalink_proto *proto; - - if (find_8022_client(type) != NULL) - return NULL; - - proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); - if (proto != NULL) { - proto->type[0] = type; - proto->type_len = 1; - proto->rcvfunc = rcvfunc; - proto->header_length = 3; - proto->datalink_header = p8022_datalink_header; - proto->string_name = "802.2"; - proto->next = p8022_list; - p8022_list = proto; - } - - return proto; -} - diff --git a/pfinet/linux-inet/p8022.h b/pfinet/linux-inet/p8022.h deleted file mode 100644 index 52c676be..00000000 --- a/pfinet/linux-inet/p8022.h +++ /dev/null @@ -1,2 +0,0 @@ -struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)); - diff --git a/pfinet/linux-inet/p8022call.h b/pfinet/linux-inet/p8022call.h deleted file mode 100644 index 14f0c2ce..00000000 --- a/pfinet/linux-inet/p8022call.h +++ /dev/null @@ -1,2 +0,0 @@ -/* Separate to keep compilation of Space.c simpler */ -extern void p8022_proto_init(struct net_proto *); diff --git a/pfinet/linux-inet/p8023.c b/pfinet/linux-inet/p8023.c deleted file mode 100644 index 7c76223d..00000000 --- a/pfinet/linux-inet/p8023.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include "datalink.h" -#include -#include - -static void -p8023_datalink_header(struct datalink_proto *dl, - struct sk_buff *skb, unsigned char *dest_node) -{ - struct device *dev = skb->dev; - unsigned long len = skb->len; - unsigned long hard_len = dev->hard_header_len; - - dev->hard_header(skb->data, dev, len - hard_len, - dest_node, NULL, len - hard_len, skb); - skb->h.raw = skb->data + hard_len; -} - -struct datalink_proto * -make_8023_client(void) -{ - struct datalink_proto *proto; - - proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); - if (proto != NULL) { - proto->type_len = 0; - proto->header_length = 0; - proto->datalink_header = p8023_datalink_header; - proto->string_name = "802.3"; - } - - return proto; -} - diff --git a/pfinet/linux-inet/packet.c b/pfinet/linux-inet/packet.c deleted file mode 100644 index ab031c81..00000000 --- a/pfinet/linux-inet/packet.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * PACKET - implements raw packet sockets. - * - * Version: @(#)packet.c 1.0.6 05/25/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Alan Cox, - * - * Fixes: - * Alan Cox : verify_area() now used correctly - * Alan Cox : new skbuff lists, look ma no backlogs! - * Alan Cox : tidied skbuff lists. - * Alan Cox : Now uses generic datagram routines I - * added. Also fixed the peek/read crash - * from all old Linux datagram code. - * Alan Cox : Uses the improved datagram code. - * Alan Cox : Added NULL's for socket options. - * Alan Cox : Re-commented the code. - * Alan Cox : Use new kernel side addressing - * Rob Janssen : Correct MTU usage. - * Dave Platt : Counter leaks caused by incorrect - * interrupt locking and some slightly - * dubious gcc output. Can you read - * compiler: it said _VOLATILE_ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include -#include "sock.h" -#include -#include -#include -#include - -/* - * We really ought to have a single public _inline_ min function! - */ - -static unsigned long min(unsigned long a, unsigned long b) -{ - if (a < b) - return(a); - return(b); -} - - -/* - * This should be the easiest of all, all we do is copy it into a buffer. - */ - -int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ - struct sock *sk; - unsigned long flags; - - /* - * When we registered the protocol we saved the socket in the data - * field for just this event. - */ - - sk = (struct sock *) pt->data; - - /* - * The SOCK_PACKET socket receives _all_ frames, and as such - * therefore needs to put the header back onto the buffer. - * (it was removed by inet_bh()). - */ - - skb->dev = dev; - skb->len += dev->hard_header_len; - - /* - * Charge the memory to the socket. This is done specifically - * to prevent sockets using all the memory up. - */ - - if (sk->rmem_alloc & 0xFF000000) { - printk("packet_rcv: sk->rmem_alloc = %ld\n", sk->rmem_alloc); - sk->rmem_alloc = 0; - } - - if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) - { -/* printk("packet_rcv: drop, %d+%d>%d\n", sk->rmem_alloc, skb->mem_len, sk->rcvbuf); */ - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return(0); - } - - save_flags(flags); - cli(); - - skb->sk = sk; - sk->rmem_alloc += skb->mem_len; - - /* - * Queue the packet up, and wake anyone waiting for it. - */ - - skb_queue_tail(&sk->receive_queue,skb); - if(!sk->dead) - sk->data_ready(sk,skb->len); - - restore_flags(flags); - - /* - * Processing complete. - */ - - release_sock(sk); /* This is now effectively surplus in this layer */ - return(0); -} - - -/* - * Output a raw packet to a device layer. This bypasses all the other - * protocol layers and you must therefore supply it with a complete frame - */ - -static int packet_sendto(struct sock *sk, unsigned char *from, int len, - int noblock, unsigned flags, struct sockaddr_in *usin, - int addr_len) -{ - struct sk_buff *skb; - struct device *dev; - struct sockaddr *saddr=(struct sockaddr *)usin; - - /* - * Check the flags. - */ - - if (flags) - return(-EINVAL); - - /* - * Get and verify the address. - */ - - if (usin) - { - if (addr_len < sizeof(*saddr)) - return(-EINVAL); - } - else - return(-EINVAL); /* SOCK_PACKET must be sent giving an address */ - - /* - * Find the device first to size check it - */ - - saddr->sa_data[13] = 0; - dev = dev_get(saddr->sa_data); - if (dev == NULL) - { - return(-ENXIO); - } - - /* - * You may not queue a frame bigger than the mtu. This is the lowest level - * raw protocol and you must do your own fragmentation at this level. - */ - - if(len>dev->mtu+dev->hard_header_len) - return -EMSGSIZE; - - skb = sk->prot->wmalloc(sk, len, 0, GFP_KERNEL); - - /* - * If the write buffer is full, then tough. At this level the user gets to - * deal with the problem - do your own algorithmic backoffs. - */ - - if (skb == NULL) - { - return(-ENOBUFS); - } - - /* - * Fill it in - */ - - skb->sk = sk; - skb->free = 1; - memcpy_fromfs(skb->data, from, len); - skb->len = len; - skb->arp = 1; /* No ARP needs doing on this (complete) frame */ - - /* - * Now send it - */ - - if (dev->flags & IFF_UP) - dev_queue_xmit(skb, dev, sk->priority); - else - kfree_skb(skb, FREE_WRITE); - return(len); -} - -/* - * A write to a SOCK_PACKET can't actually do anything useful and will - * always fail but we include it for completeness and future expansion. - */ - -static int packet_write(struct sock *sk, unsigned char *buff, - int len, int noblock, unsigned flags) -{ - return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0)); -} - -/* - * Close a SOCK_PACKET socket. This is fairly simple. We immediately go - * to 'closed' state and remove our protocol entry in the device list. - * The release_sock() will destroy the socket if a user has closed the - * file side of the object. - */ - -static void packet_close(struct sock *sk, int timeout) -{ - sk->inuse = 1; - sk->state = TCP_CLOSE; - dev_remove_pack((struct packet_type *)sk->pair); - kfree_s((void *)sk->pair, sizeof(struct packet_type)); - sk->pair = NULL; - release_sock(sk); -} - -/* - * Create a packet of type SOCK_PACKET. We do one slightly irregular - * thing here that wants tidying up. We borrow the 'pair' pointer in - * the socket object so we can find the packet_type entry in the - * device list. The reverse is easy as we use the data field of the - * packet type to point to our socket. - */ - -static int packet_init(struct sock *sk) -{ - struct packet_type *p; - - p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) - return(-ENOMEM); - - p->func = packet_rcv; - p->type = sk->num; - p->data = (void *)sk; - p->dev = NULL; - dev_add_pack(p); - - /* - * We need to remember this somewhere. - */ - - sk->pair = (struct sock *)p; - - return(0); -} - - -/* - * Pull a packet from our receive queue and hand it to the user. - * If necessary we block. - */ - -int packet_recvfrom(struct sock *sk, unsigned char *to, int len, - int noblock, unsigned flags, struct sockaddr_in *sin, - int *addr_len) -{ - int copied=0; - struct sk_buff *skb; - struct sockaddr *saddr; - int err; - int truesize; - - saddr = (struct sockaddr *)sin; - - if (sk->shutdown & RCV_SHUTDOWN) - return(0); - - /* - * If the address length field is there to be filled in, we fill - * it in now. - */ - - if (addr_len) - *addr_len=sizeof(*saddr); - - /* - * Call the generic datagram receiver. This handles all sorts - * of horrible races and re-entrancy so we can forget about it - * in the protocol layers. - */ - - skb=skb_recv_datagram(sk,flags,noblock,&err); - - /* - * An error occurred so return it. Because skb_recv_datagram() - * handles the blocking we don't see and worry about blocking - * retries. - */ - - if(skb==NULL) - return err; - - /* - * You lose any data beyond the buffer you gave. If it worries a - * user program they can ask the device for its MTU anyway. - */ - - truesize = skb->len; - copied = min(len, truesize); - - memcpy_tofs(to, skb->data, copied); /* We can't use skb_copy_datagram here */ - - /* - * Copy the address. - */ - - if (saddr) - { - saddr->sa_family = skb->dev->type; - memcpy(saddr->sa_data,skb->dev->name, 14); - } - - /* - * Free or return the buffer as appropriate. Again this hides all the - * races and re-entrancy issues from us. - */ - - skb_free_datagram(skb); - - /* - * We are done. - */ - - release_sock(sk); - return(truesize); -} - - -/* - * A packet read can succeed and is just the same as a recvfrom but without the - * addresses being recorded. - */ - -int packet_read(struct sock *sk, unsigned char *buff, - int len, int noblock, unsigned flags) -{ - return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); -} - - -/* - * This structure declares to the lower layer socket subsystem currently - * incorrectly embedded in the IP code how to behave. This interface needs - * a lot of work and will change. - */ - -struct proto packet_prot = -{ - sock_wmalloc, - sock_rmalloc, - sock_wfree, - sock_rfree, - sock_rspace, - sock_wspace, - packet_close, - packet_read, - packet_write, - packet_sendto, - packet_recvfrom, - ip_build_header, /* Not actually used */ - NULL, - NULL, - ip_queue_xmit, /* These two are not actually used */ - NULL, - NULL, - NULL, - NULL, - datagram_select, - NULL, - packet_init, - NULL, - NULL, /* No set/get socket options */ - NULL, - 128, - 0, - {NULL,}, - "PACKET", - 0, 0 -}; diff --git a/pfinet/linux-inet/pe2.c b/pfinet/linux-inet/pe2.c deleted file mode 100644 index 856e454b..00000000 --- a/pfinet/linux-inet/pe2.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include "datalink.h" -#include -#include - -static void -pEII_datalink_header(struct datalink_proto *dl, - struct sk_buff *skb, unsigned char *dest_node) -{ - struct device *dev = skb->dev; - unsigned long len = skb->len; - unsigned long hard_len = dev->hard_header_len; - - dev->hard_header(skb->data, dev, ETH_P_IPX, - dest_node, NULL, len - hard_len, skb); - skb->h.raw = skb->data + hard_len; -} - -struct datalink_proto * -make_EII_client(void) -{ - struct datalink_proto *proto; - - proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); - if (proto != NULL) { - proto->type_len = 0; - proto->header_length = 0; - proto->datalink_header = pEII_datalink_header; - proto->string_name = "EtherII"; - } - - return proto; -} - diff --git a/pfinet/linux-inet/proc.c b/pfinet/linux-inet/proc.c deleted file mode 100644 index aec473a2..00000000 --- a/pfinet/linux-inet/proc.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * This file implements the various access functions for the - * PROC file system. It is mainly used for debugging and - * statistics. - * - * Version: @(#)proc.c 1.0.5 05/27/93 - * - * Authors: Fred N. van Kempen, - * Gerald J. Heim, - * Fred Baumgarten, - * Erik Schoenfelder, - * - * Fixes: - * Alan Cox : UDP sockets show the rxqueue/txqueue - * using hint flag for the netinfo. - * Pauline Middelink : identd support - * Alan Cox : Make /proc safer. - * Erik Schoenfelder : /proc/net/snmp - * Alan Cox : Handle dead sockets properly. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "icmp.h" -#include "protocol.h" -#include "tcp.h" -#include "udp.h" -#include -#include "sock.h" -#include "raw.h" - -/* - * Get__netinfo returns the length of that string. - * - * KNOWN BUGS - * As in get_unix_netinfo, the buffer might be too small. If this - * happens, get__netinfo returns only part of the available infos. - */ -static int -get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length) -{ - struct sock **s_array; - struct sock *sp; - int i; - int timer_active; - unsigned long dest, src; - unsigned short destp, srcp; - int len=0; - off_t pos=0; - off_t begin=0; - - s_array = pro->sock_array; - len+=sprintf(buffer, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n"); -/* - * This was very pretty but didn't work when a socket is destroyed at the wrong moment - * (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing - * with timers we just concede defeat and cli(). - */ - for(i = 0; i < SOCK_ARRAY_SIZE; i++) - { - cli(); - sp = s_array[i]; - while(sp != NULL) - { - dest = sp->daddr; - src = sp->saddr; - destp = sp->dummy_th.dest; - srcp = sp->dummy_th.source; - - /* Since we are Little Endian we need to swap the bytes :-( */ - destp = ntohs(destp); - srcp = ntohs(srcp); - timer_active = del_timer(&sp->timer); - if (!timer_active) - sp->timer.expires = 0; - len+=sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d %d\n", - i, src, srcp, dest, destp, sp->state, - format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, - format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc, - timer_active, sp->timer.expires, (unsigned) sp->retransmits, - sp->socket?SOCK_INODE(sp->socket)->i_uid:0, - timer_active?sp->timeout:0); - if (timer_active) - add_timer(&sp->timer); - /* - * All sockets with (port mod SOCK_ARRAY_SIZE) = i - * are kept in sock_array[i], so we must follow the - * 'next' link to get them all. - */ - sp = sp->next; - pos=begin+len; - if(posoffset+length) - break; - } - sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up - before this will clear before we jump back and cli, so it's not as bad as it looks */ - if(pos>offset+length) - break; - } - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - - -int tcp_get_info(char *buffer, char **start, off_t offset, int length) -{ - return get__netinfo(&tcp_prot, buffer,0, start, offset, length); -} - - -int udp_get_info(char *buffer, char **start, off_t offset, int length) -{ - return get__netinfo(&udp_prot, buffer,1, start, offset, length); -} - - -int raw_get_info(char *buffer, char **start, off_t offset, int length) -{ - return get__netinfo(&raw_prot, buffer,1, start, offset, length); -} - - -/* - * Report socket allocation statistics [mea@utu.fi] - */ -int afinet_get_info(char *buffer, char **start, off_t offset, int length) -{ - /* From net/socket.c */ - extern int socket_get_info(char *, char **, off_t, int); -#ifndef _HURD_ - extern struct proto packet_prot; - int len = socket_get_info(buffer,start,offset,length); -#else - int len = 0; -#endif - - - len += sprintf(buffer+len,"SOCK_ARRAY_SIZE=%d\n",SOCK_ARRAY_SIZE); - len += sprintf(buffer+len,"TCP: inuse %d highest %d\n", - tcp_prot.inuse, tcp_prot.highestinuse); - len += sprintf(buffer+len,"UDP: inuse %d highest %d\n", - udp_prot.inuse, udp_prot.highestinuse); - len += sprintf(buffer+len,"RAW: inuse %d highest %d\n", - raw_prot.inuse, raw_prot.highestinuse); -#ifndef _HURD_ - len += sprintf(buffer+len,"PAC: inuse %d highest %d\n", - packet_prot.inuse, packet_prot.highestinuse); -#endif - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - return len; -} - - -/* - * Called from the PROCfs module. This outputs /proc/net/snmp. - */ - -int snmp_get_info(char *buffer, char **start, off_t offset, int length) -{ - extern struct tcp_mib tcp_statistics; - extern struct udp_mib udp_statistics; - int len; -/* - extern unsigned long tcp_rx_miss, tcp_rx_hit1,tcp_rx_hit2; -*/ - - len = sprintf (buffer, - "Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n" - "Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - ip_statistics.IpForwarding, ip_statistics.IpDefaultTTL, - ip_statistics.IpInReceives, ip_statistics.IpInHdrErrors, - ip_statistics.IpInAddrErrors, ip_statistics.IpForwDatagrams, - ip_statistics.IpInUnknownProtos, ip_statistics.IpInDiscards, - ip_statistics.IpInDelivers, ip_statistics.IpOutRequests, - ip_statistics.IpOutDiscards, ip_statistics.IpOutNoRoutes, - ip_statistics.IpReasmTimeout, ip_statistics.IpReasmReqds, - ip_statistics.IpReasmOKs, ip_statistics.IpReasmFails, - ip_statistics.IpFragOKs, ip_statistics.IpFragFails, - ip_statistics.IpFragCreates); - - len += sprintf (buffer + len, - "Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n" - "Icmp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - icmp_statistics.IcmpInMsgs, icmp_statistics.IcmpInErrors, - icmp_statistics.IcmpInDestUnreachs, icmp_statistics.IcmpInTimeExcds, - icmp_statistics.IcmpInParmProbs, icmp_statistics.IcmpInSrcQuenchs, - icmp_statistics.IcmpInRedirects, icmp_statistics.IcmpInEchos, - icmp_statistics.IcmpInEchoReps, icmp_statistics.IcmpInTimestamps, - icmp_statistics.IcmpInTimestampReps, icmp_statistics.IcmpInAddrMasks, - icmp_statistics.IcmpInAddrMaskReps, icmp_statistics.IcmpOutMsgs, - icmp_statistics.IcmpOutErrors, icmp_statistics.IcmpOutDestUnreachs, - icmp_statistics.IcmpOutTimeExcds, icmp_statistics.IcmpOutParmProbs, - icmp_statistics.IcmpOutSrcQuenchs, icmp_statistics.IcmpOutRedirects, - icmp_statistics.IcmpOutEchos, icmp_statistics.IcmpOutEchoReps, - icmp_statistics.IcmpOutTimestamps, icmp_statistics.IcmpOutTimestampReps, - icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps); - - len += sprintf (buffer + len, - "Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs\n" - "Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin, - tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn, - tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens, - tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets, - tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs, - tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs); - - len += sprintf (buffer + len, - "Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n", - udp_statistics.UdpInDatagrams, udp_statistics.UdpNoPorts, - udp_statistics.UdpInErrors, udp_statistics.UdpOutDatagrams); -/* - len += sprintf( buffer + len, - "TCP fast path RX: H2: %ul H1: %ul L: %ul\n", - tcp_rx_hit2,tcp_rx_hit1,tcp_rx_miss); -*/ - - if (offset >= len) - { - *start = buffer; - return 0; - } - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - return len; -} - diff --git a/pfinet/linux-inet/protocol.c b/pfinet/linux-inet/protocol.c deleted file mode 100644 index a47d27cd..00000000 --- a/pfinet/linux-inet/protocol.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * INET protocol dispatch tables. - * - * Version: @(#)protocol.c 1.0.5 05/25/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : Ahah! udp icmp errors don't work because - * udp_err is never called! - * Alan Cox : Added new fields for init and ready for - * proper fragmentation (_NO_ 4K limits!) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include "tcp.h" -#include -#include "sock.h" -#include "icmp.h" -#include "udp.h" -#include - - -static struct inet_protocol tcp_protocol = { - tcp_rcv, /* TCP handler */ - NULL, /* No fragment handler (and won't be for a long time) */ - tcp_err, /* TCP error control */ - NULL, /* next */ - IPPROTO_TCP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "TCP" /* name */ -}; - - -static struct inet_protocol udp_protocol = { - udp_rcv, /* UDP handler */ - NULL, /* Will be UDP fraglist handler */ - udp_err, /* UDP error control */ - &tcp_protocol, /* next */ - IPPROTO_UDP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "UDP" /* name */ -}; - - -static struct inet_protocol icmp_protocol = { - icmp_rcv, /* ICMP handler */ - NULL, /* ICMP never fragments anyway */ - NULL, /* ICMP error control */ - &udp_protocol, /* next */ - IPPROTO_ICMP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "ICMP" /* name */ -}; - -#ifndef CONFIG_IP_MULTICAST -struct inet_protocol *inet_protocol_base = &icmp_protocol; -#else -static struct inet_protocol igmp_protocol = { - igmp_rcv, /* IGMP handler */ - NULL, /* IGMP never fragments anyway */ - NULL, /* IGMP error control */ - &icmp_protocol, /* next */ - IPPROTO_IGMP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "IGMP" /* name */ -}; - -struct inet_protocol *inet_protocol_base = &igmp_protocol; -#endif - -struct inet_protocol *inet_protos[MAX_INET_PROTOS] = { - NULL -}; - - -struct inet_protocol * -inet_get_protocol(unsigned char prot) -{ - unsigned char hash; - struct inet_protocol *p; - - hash = prot & (MAX_INET_PROTOS - 1); - for (p = inet_protos[hash] ; p != NULL; p=p->next) { - if (p->protocol == prot) return((struct inet_protocol *) p); - } - return(NULL); -} - - -void -inet_add_protocol(struct inet_protocol *prot) -{ - unsigned char hash; - struct inet_protocol *p2; - - hash = prot->protocol & (MAX_INET_PROTOS - 1); - prot ->next = inet_protos[hash]; - inet_protos[hash] = prot; - prot->copy = 0; - - /* Set the copy bit if we need to. */ - p2 = (struct inet_protocol *) prot->next; - while(p2 != NULL) { - if (p2->protocol == prot->protocol) { - prot->copy = 1; - break; - } - p2 = (struct inet_protocol *) prot->next; - } -} - - -int -inet_del_protocol(struct inet_protocol *prot) -{ - struct inet_protocol *p; - struct inet_protocol *lp = NULL; - unsigned char hash; - - hash = prot->protocol & (MAX_INET_PROTOS - 1); - if (prot == inet_protos[hash]) { - inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next; - return(0); - } - - p = (struct inet_protocol *) inet_protos[hash]; - while(p != NULL) { - /* - * We have to worry if the protocol being deleted is - * the last one on the list, then we may need to reset - * someone's copied bit. - */ - if (p->next != NULL && p->next == prot) { - /* - * if we are the last one with this protocol and - * there is a previous one, reset its copy bit. - */ - if (p->copy == 0 && lp != NULL) lp->copy = 0; - p->next = prot->next; - return(0); - } - - if (p->next != NULL && p->next->protocol == prot->protocol) { - lp = p; - } - - p = (struct inet_protocol *) p->next; - } - return(-1); -} diff --git a/pfinet/linux-inet/protocol.h b/pfinet/linux-inet/protocol.h deleted file mode 100644 index 3e0b6fb3..00000000 --- a/pfinet/linux-inet/protocol.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the protocol dispatcher. - * - * Version: @(#)protocol.h 1.0.2 05/07/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Changes: - * Alan Cox : Added a name field and a frag handler - * field for later. - */ - -#ifndef _PROTOCOL_H -#define _PROTOCOL_H - - -#define MAX_INET_PROTOS 32 /* Must be a power of 2 */ - - -/* This is used to register protocols. */ -struct inet_protocol { - int (*handler)(struct sk_buff *skb, struct device *dev, - struct options *opt, unsigned long daddr, - unsigned short len, unsigned long saddr, - int redo, struct inet_protocol *protocol); - int (*frag_handler)(struct sk_buff *skb, struct device *dev, - struct options *opt, unsigned long daddr, - unsigned short len, unsigned long saddr, - int redo, struct inet_protocol *protocol); - void (*err_handler)(int err, unsigned char *buff, - unsigned long daddr, - unsigned long saddr, - struct inet_protocol *protocol); - struct inet_protocol *next; - unsigned char protocol; - unsigned char copy:1; - void *data; - char *name; -}; - - -extern struct inet_protocol *inet_protocol_base; -extern struct inet_protocol *inet_protos[MAX_INET_PROTOS]; - - -extern void inet_add_protocol(struct inet_protocol *prot); -extern int inet_del_protocol(struct inet_protocol *prot); - - -#endif /* _PROTOCOL_H */ diff --git a/pfinet/linux-inet/psnap.c b/pfinet/linux-inet/psnap.c deleted file mode 100644 index 287b3353..00000000 --- a/pfinet/linux-inet/psnap.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SNAP data link layer. Derived from 802.2 - * - * Alan Cox , from the 802.2 layer by Greg Page. - * Merged in additions from Greg Page's psnap.c. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include "datalink.h" -#include "p8022.h" -#include "psnap.h" -#include -#include - -static struct datalink_proto *snap_list = NULL; -static struct datalink_proto *snap_dl = NULL; /* 802.2 DL for SNAP */ - -/* - * Find a snap client by matching the 5 bytes. - */ - -static struct datalink_proto *find_snap_client(unsigned char *desc) -{ - struct datalink_proto *proto; - - for (proto = snap_list; proto != NULL && memcmp(proto->type, desc, 5) ; proto = proto->next); - return proto; -} - -/* - * A SNAP packet has arrived - */ - -int snap_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ - static struct packet_type psnap_packet_type = - { - 0, - NULL, /* All Devices */ - snap_rcv, - NULL, - NULL, - }; - - struct datalink_proto *proto; - - proto = find_snap_client(skb->h.raw); - if (proto != NULL) - { - /* - * Pass the frame on. - */ - - skb->h.raw += 5; - skb->len -= 5; - if (psnap_packet_type.type == 0) - psnap_packet_type.type=htons(ETH_P_SNAP); - return proto->rcvfunc(skb, dev, &psnap_packet_type); - } - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return 0; -} - -/* - * Put a SNAP header on a frame and pass to 802.2 - */ - -static void snap_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node) -{ - struct device *dev = skb->dev; - unsigned char *rawp; - - rawp = skb->data + snap_dl->header_length+dev->hard_header_len; - memcpy(rawp,dl->type,5); - skb->h.raw = rawp+5; - snap_dl->datalink_header(snap_dl, skb, dest_node); -} - -/* - * Set up the SNAP layer - */ - -void snap_proto_init(struct net_proto *pro) -{ - snap_dl=register_8022_client(0xAA, snap_rcv); - if(snap_dl==NULL) - printk("SNAP - unable to register with 802.2\n"); -} - -/* - * Register SNAP clients. We don't yet use this for IP or IPX. - */ - -struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)) -{ - struct datalink_proto *proto; - - if (find_snap_client(desc) != NULL) - return NULL; - - proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); - if (proto != NULL) - { - memcpy(proto->type, desc,5); - proto->type_len = 5; - proto->rcvfunc = rcvfunc; - proto->header_length = 5+snap_dl->header_length; - proto->datalink_header = snap_datalink_header; - proto->string_name = "SNAP"; - proto->next = snap_list; - snap_list = proto; - } - - return proto; -} - diff --git a/pfinet/linux-inet/psnap.h b/pfinet/linux-inet/psnap.h deleted file mode 100644 index b69859db..00000000 --- a/pfinet/linux-inet/psnap.h +++ /dev/null @@ -1,2 +0,0 @@ -struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)); - diff --git a/pfinet/linux-inet/psnapcall.h b/pfinet/linux-inet/psnapcall.h deleted file mode 100644 index 9da5763c..00000000 --- a/pfinet/linux-inet/psnapcall.h +++ /dev/null @@ -1,2 +0,0 @@ -/* Separate to keep compilation of Space.c simpler */ -extern void snap_proto_init(struct net_proto *); diff --git a/pfinet/linux-inet/rarp.c b/pfinet/linux-inet/rarp.c deleted file mode 100644 index 72924bb2..00000000 --- a/pfinet/linux-inet/rarp.c +++ /dev/null @@ -1,491 +0,0 @@ -/* linux/net/inet/rarp.c - * - * Copyright (C) 1994 by Ross Martin - * Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche - * - * This module implements the Reverse Address Resolution Protocol - * (RARP, RFC 903), which is used to convert low level addresses such - * as ethernet addresses into high level addresses such as IP addresses. - * The most common use of RARP is as a means for a diskless workstation - * to discover its IP address during a network boot. - * - ** - *** WARNING:::::::::::::::::::::::::::::::::WARNING - **** - ***** SUN machines seem determined to boot solely from the person who - **** answered their RARP query. NEVER add a SUN to your RARP table - *** unless you have all the rest to boot the box from it. - ** - * - * Currently, only ethernet address -> IP address is likely to work. - * (Is RARP ever used for anything else?) - * - * This code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "route.h" -#include "protocol.h" -#include "tcp.h" -#include -#include "sock.h" -#include "arp.h" -#include "rarp.h" -#ifdef CONFIG_AX25 -#include "ax25.h" -#endif - -#ifdef CONFIG_INET_RARP - -/* - * This structure defines the RARP mapping cache. As long as we make - * changes in this structure, we keep interrupts off. - */ - -struct rarp_table -{ - struct rarp_table *next; /* Linked entry list */ - unsigned long ip; /* ip address of entry */ - unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ - unsigned char hlen; /* Length of hardware address */ - unsigned char htype; /* Type of hardware in use */ - struct device *dev; /* Device the entry is tied to */ -}; - -struct rarp_table *rarp_tables = NULL; - - -static struct packet_type rarp_packet_type = -{ - 0, /* Should be: __constant_htons(ETH_P_RARP) - but this _doesn't_ come out constant! */ - 0, /* copy */ - rarp_rcv, - NULL, - NULL -}; - -static initflag = 1; - -/* - * Called once when data first added to rarp cache with ioctl. - */ - -static void rarp_init (void) -{ - /* Register the packet type */ - rarp_packet_type.type=htons(ETH_P_RARP); - dev_add_pack(&rarp_packet_type); -} - -/* - * Release the memory for this entry. - */ - -static inline void rarp_release_entry(struct rarp_table *entry) -{ - kfree_s(entry, sizeof(struct rarp_table)); - return; -} - -/* - * Delete a RARP mapping entry in the cache. - */ - -static void rarp_destroy(unsigned long ip_addr) -{ - struct rarp_table *entry; - struct rarp_table **pentry; - - cli(); - pentry = &rarp_tables; - while ((entry = *pentry) != NULL) - { - if (entry->ip == ip_addr) - { - *pentry = entry->next; - sti(); - rarp_release_entry(entry); - return; - } - pentry = &entry->next; - } - sti(); -} - - -/* - * Receive an arp request by the device layer. Maybe it should be - * rewritten to use the incoming packet for the reply. The current - * "overhead" time isn't that high... - */ - -int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ -/* - * We shouldn't use this type conversion. Check later. - */ - struct arphdr *rarp = (struct arphdr *)skb->h.raw; - unsigned char *rarp_ptr = (unsigned char *)(rarp+1); - struct rarp_table *entry; - long sip,tip; - unsigned char *sha,*tha; /* s for "source", t for "target" */ - -/* - * If this test doesn't pass, it's not IP, or we should ignore it anyway - */ - - if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd) - || dev->flags&IFF_NOARP) - { - kfree_skb(skb, FREE_READ); - return 0; - } - -/* - * If it's not a RARP request, delete it. - */ - if (rarp->ar_op != htons(ARPOP_RREQUEST)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - -/* - * For now we will only deal with IP addresses. - */ - - if ( -#ifdef CONFIG_AX25 - (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) || -#endif - (rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) - || rarp->ar_pln != 4) - { - /* - * This packet is not for us. Remove it. - */ - kfree_skb(skb, FREE_READ); - return 0; -} - -/* - * Extract variable width fields - */ - - sha=rarp_ptr; - rarp_ptr+=dev->addr_len; - memcpy(&sip,rarp_ptr,4); - rarp_ptr+=4; - tha=rarp_ptr; - rarp_ptr+=dev->addr_len; - memcpy(&tip,rarp_ptr,4); - -/* - * Process entry. Use tha for table lookup according to RFC903. - */ - - cli(); - for (entry = rarp_tables; entry != NULL; entry = entry->next) - if (!memcmp(entry->ha, tha, rarp->ar_hln)) - break; - - if (entry != NULL) - { - sip=entry->ip; - sti(); - - arp_send(ARPOP_RREPLY, ETH_P_RARP, sip, dev, dev->pa_addr, sha, - dev->dev_addr); - } - else - sti(); - - kfree_skb(skb, FREE_READ); - return 0; -} - - -/* - * Set (create) a RARP cache entry. - */ - -static int rarp_req_set(struct arpreq *req) -{ - struct arpreq r; - struct rarp_table *entry; - struct sockaddr_in *si; - int htype, hlen; - unsigned long ip; - struct rtable *rt; - - memcpy_fromfs(&r, req, sizeof(r)); - - /* - * We only understand about IP addresses... - */ - - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - - switch (r.arp_ha.sa_family) - { - case ARPHRD_ETHER: - htype = ARPHRD_ETHER; - hlen = ETH_ALEN; - break; -#ifdef CONFIG_AX25 - case ARPHRD_AX25: - htype = ARPHRD_AX25; - hlen = 7; - break; -#endif - default: - return -EPFNOSUPPORT; - } - - si = (struct sockaddr_in *) &r.arp_pa; - ip = si->sin_addr.s_addr; - if (ip == 0) - { - printk("RARP: SETRARP: requested PA is 0.0.0.0 !\n"); - return -EINVAL; - } - -/* - * Is it reachable directly ? - */ - - rt = ip_rt_route(ip, NULL, NULL); - if (rt == NULL) - return -ENETUNREACH; - -/* - * Is there an existing entry for this address? Find out... - */ - - cli(); - for (entry = rarp_tables; entry != NULL; entry = entry->next) - if (entry->ip == ip) - break; - -/* - * If no entry was found, create a new one. - */ - - if (entry == NULL) - { - entry = (struct rarp_table *) kmalloc(sizeof(struct rarp_table), - GFP_ATOMIC); - if (entry == NULL) - { - sti(); - return -ENOMEM; - } - if(initflag) - { - rarp_init(); - initflag=0; - } - - entry->next = rarp_tables; - rarp_tables = entry; - } - - entry->ip = ip; - entry->hlen = hlen; - entry->htype = htype; - memcpy(&entry->ha, &r.arp_ha.sa_data, hlen); - entry->dev = rt->rt_dev; - - sti(); - - return 0; -} - - -/* - * Get a RARP cache entry. - */ - -static int rarp_req_get(struct arpreq *req) -{ - struct arpreq r; - struct rarp_table *entry; - struct sockaddr_in *si; - unsigned long ip; - -/* - * We only understand about IP addresses... - */ - - memcpy_fromfs(&r, req, sizeof(r)); - - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - -/* - * Is there an existing entry for this address? - */ - - si = (struct sockaddr_in *) &r.arp_pa; - ip = si->sin_addr.s_addr; - - cli(); - for (entry = rarp_tables; entry != NULL; entry = entry->next) - if (entry->ip == ip) - break; - - if (entry == NULL) - { - sti(); - return -ENXIO; - } - -/* - * We found it; copy into structure. - */ - - memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen); - r.arp_ha.sa_family = entry->htype; - sti(); - -/* - * Copy the information back - */ - - memcpy_tofs(req, &r, sizeof(r)); - return 0; -} - - -/* - * Handle a RARP layer I/O control request. - */ - -int rarp_ioctl(unsigned int cmd, void *arg) -{ - struct arpreq r; - struct sockaddr_in *si; - int err; - - switch(cmd) - { - case SIOCDRARP: - if (!suser()) - return -EPERM; - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); - if(err) - return err; - memcpy_fromfs(&r, arg, sizeof(r)); - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - si = (struct sockaddr_in *) &r.arp_pa; - rarp_destroy(si->sin_addr.s_addr); - return 0; - - case SIOCGRARP: - err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq)); - if(err) - return err; - return rarp_req_get((struct arpreq *)arg); - case SIOCSRARP: - if (!suser()) - return -EPERM; - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); - if(err) - return err; - return rarp_req_set((struct arpreq *)arg); - default: - return -EINVAL; - } - - /*NOTREACHED*/ - return 0; -} - -int rarp_get_info(char *buffer, char **start, off_t offset, int length) -{ - int len=0; - off_t begin=0; - off_t pos=0; - int size; - struct rarp_table *entry; - char ipbuffer[20]; - unsigned long netip; - if(initflag) - { - size = sprintf(buffer,"RARP disabled until entries added to cache.\n"); - pos+=size; - len+=size; - } - else - { - size = sprintf(buffer, - "IP address HW type HW address\n"); - pos+=size; - len+=size; - - cli(); - for(entry=rarp_tables; entry!=NULL; entry=entry->next) - { - netip=htonl(entry->ip); /* switch to network order */ - sprintf(ipbuffer,"%d.%d.%d.%d", - (unsigned int)(netip>>24)&255, - (unsigned int)(netip>>16)&255, - (unsigned int)(netip>>8)&255, - (unsigned int)(netip)&255); - - size = sprintf(buffer+len, - "%-17s%-20s%02x:%02x:%02x:%02x:%02x:%02x\n", - ipbuffer, - "10Mbps Ethernet", - (unsigned int)entry->ha[0], - (unsigned int)entry->ha[1], - (unsigned int)entry->ha[2], - (unsigned int)entry->ha[3], - (unsigned int)entry->ha[4], - (unsigned int)entry->ha[5]); - - len+=size; - pos=begin+len; - - if(posoffset+length) - break; - } - sti(); - } - - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len=length; /* Ending slop */ - return len; -} - -#endif diff --git a/pfinet/linux-inet/rarp.h b/pfinet/linux-inet/rarp.h deleted file mode 100644 index 02ee7784..00000000 --- a/pfinet/linux-inet/rarp.h +++ /dev/null @@ -1,14 +0,0 @@ -/* linux/net/inet/rarp.h */ -#ifndef _RARP_H -#define _RARP_H - -extern int rarp_ioctl(unsigned int cmd, void *arg); -extern int rarp_rcv(struct sk_buff *skb, - struct device *dev, - struct packet_type *pt); -extern int rarp_get_info(char *buffer, - char **start, - off_t offset, - int length); -#endif /* _RARP_H */ - diff --git a/pfinet/linux-inet/raw.c b/pfinet/linux-inet/raw.c deleted file mode 100644 index b7d34a37..00000000 --- a/pfinet/linux-inet/raw.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * RAW - implementation of IP "raw" sockets. - * - * Version: @(#)raw.c 1.0.4 05/25/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : verify_area() fixed up - * Alan Cox : ICMP error handling - * Alan Cox : EMSGSIZE if you send too big a packet - * Alan Cox : Now uses generic datagrams and shared skbuff - * library. No more peek crashes, no more backlogs - * Alan Cox : Checks sk->broadcast. - * Alan Cox : Uses skb_free_datagram/skb_copy_datagram - * Alan Cox : Raw passes ip options too - * Alan Cox : Setsocketopt added - * Alan Cox : Fixed error return for broadcasts - * Alan Cox : Removed wake_up calls - * Alan Cox : Use ttl/tos - * Alan Cox : Cleaned up old debugging - * Alan Cox : Use new kernel side addresses - * Arnt Gulbrandsen : Fixed MSG_DONTROUTE in raw sockets. - * Alan Cox : BSD style RAW socket demultiplexing. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include -#include "sock.h" -#include "icmp.h" -#include "udp.h" - - -static inline unsigned long min(unsigned long a, unsigned long b) -{ - if (a < b) - return(a); - return(b); -} - - -/* raw_err gets called by the icmp module. */ -void raw_err (int err, unsigned char *header, unsigned long daddr, - unsigned long saddr, struct inet_protocol *protocol) -{ - struct sock *sk; - - if (protocol == NULL) - return; - sk = (struct sock *) protocol->data; - if (sk == NULL) - return; - - /* This is meaningless in raw sockets. */ - if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) - { - if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2; - return; - } - - sk->err = icmp_err_convert[err & 0xff].error; - sk->error_report(sk); - - return; -} - - -/* - * This should be the easiest of all, all we do is - * copy it into a buffer. All demultiplexing is done - * in ip.c - */ - -int raw_rcv(struct sock *sk, struct sk_buff *skb, struct device *dev, long saddr, long daddr) -{ - /* Now we need to copy this into memory. */ - skb->sk = sk; - skb->len = ntohs(skb->ip_hdr->tot_len); - skb->h.raw = (unsigned char *) skb->ip_hdr; - skb->dev = dev; - skb->saddr = daddr; - skb->daddr = saddr; - - /* Charge it to the socket. */ - - if(sock_queue_rcv_skb(sk,skb)<0) - { - ip_statistics.IpInDiscards++; - skb->sk=NULL; - kfree_skb(skb, FREE_READ); - return(0); - } - - ip_statistics.IpInDelivers++; - release_sock(sk); - return(0); -} - -/* - * Send a RAW IP packet. - */ - -static int raw_sendto(struct sock *sk, unsigned char *from, - int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len) -{ - struct sk_buff *skb; - struct device *dev=NULL; - struct sockaddr_in sin; - int tmp; - int err; - - /* - * Check the flags. Only MSG_DONTROUTE is permitted. - */ - - if (flags & MSG_OOB) /* Mirror BSD error message compatibility */ - return -EOPNOTSUPP; - - if (flags & ~MSG_DONTROUTE) - return(-EINVAL); - /* - * Get and verify the address. - */ - - if (usin) - { - if (addr_len < sizeof(sin)) - return(-EINVAL); - memcpy(&sin, usin, sizeof(sin)); - if (sin.sin_family && sin.sin_family != AF_INET) - return(-EINVAL); - } - else - { - if (sk->state != TCP_ESTABLISHED) - return(-EINVAL); - sin.sin_family = AF_INET; - sin.sin_port = sk->protocol; - sin.sin_addr.s_addr = sk->daddr; - } - if (sin.sin_port == 0) - sin.sin_port = sk->protocol; - - if (sin.sin_addr.s_addr == INADDR_ANY) - sin.sin_addr.s_addr = ip_my_addr(); - - if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) - return -EACCES; - - skb=sock_alloc_send_skb(sk, len+sk->prot->max_header, noblock, &err); - if(skb==NULL) - return err; - - skb->sk = sk; - skb->free = 1; - skb->localroute = sk->localroute | (flags&MSG_DONTROUTE); - - tmp = sk->prot->build_header(skb, sk->saddr, - sin.sin_addr.s_addr, &dev, - sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl); - if (tmp < 0) - { - kfree_skb(skb,FREE_WRITE); - release_sock(sk); - return(tmp); - } - - memcpy_fromfs(skb->data + tmp, from, len); - - /* - * If we are using IPPROTO_RAW, we need to fill in the source address in - * the IP header - */ - - if(sk->protocol==IPPROTO_RAW) - { - unsigned char *buff; - struct iphdr *iph; - - buff = skb->data; - buff += tmp; - - iph = (struct iphdr *)buff; - iph->saddr = sk->saddr; - } - - skb->len = tmp + len; - - sk->prot->queue_xmit(sk, dev, skb, 1); - release_sock(sk); - return(len); -} - - -static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock, - unsigned flags) -{ - return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0)); -} - - -static void raw_close(struct sock *sk, int timeout) -{ - sk->state = TCP_CLOSE; -} - - -static int raw_init(struct sock *sk) -{ - return(0); -} - - -/* - * This should be easy, if there is something there - * we return it, otherwise we block. - */ - -int raw_recvfrom(struct sock *sk, unsigned char *to, int len, - int noblock, unsigned flags, struct sockaddr_in *sin, - int *addr_len) -{ - int copied=0; - struct sk_buff *skb; - int err; - int truesize; - - if (flags & MSG_OOB) - return -EOPNOTSUPP; - - if (sk->shutdown & RCV_SHUTDOWN) - return(0); - - if (addr_len) - *addr_len=sizeof(*sin); - - skb=skb_recv_datagram(sk,flags,noblock,&err); - if(skb==NULL) - return err; - - truesize=skb->len; - copied = min(len, truesize); - - skb_copy_datagram(skb, 0, to, copied); - sk->stamp=skb->stamp; - - /* Copy the address. */ - if (sin) - { - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = skb->daddr; - } - skb_free_datagram(skb); - release_sock(sk); - return (truesize); /* len not copied. BSD returns the true size of the message so you know a bit fell off! */ -} - - -int raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,unsigned flags) -{ - return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); -} - - -struct proto raw_prot = { - sock_wmalloc, - sock_rmalloc, - sock_wfree, - sock_rfree, - sock_rspace, - sock_wspace, - raw_close, - raw_read, - raw_write, - raw_sendto, - raw_recvfrom, - ip_build_header, - udp_connect, - NULL, - ip_queue_xmit, - NULL, - NULL, - NULL, - NULL, - datagram_select, - NULL, - raw_init, - NULL, - ip_setsockopt, - ip_getsockopt, - 128, - 0, - {NULL,}, - "RAW", - 0, 0 -}; diff --git a/pfinet/linux-inet/raw.h b/pfinet/linux-inet/raw.h deleted file mode 100644 index 8f1cf0c2..00000000 --- a/pfinet/linux-inet/raw.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the RAW-IP module. - * - * Version: @(#)raw.h 1.0.2 05/07/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _RAW_H -#define _RAW_H - - -extern struct proto raw_prot; - - -extern void raw_err(int err, unsigned char *header, unsigned long daddr, - unsigned long saddr, struct inet_protocol *protocol); -extern int raw_recvfrom(struct sock *sk, unsigned char *to, - int len, int noblock, unsigned flags, - struct sockaddr_in *sin, int *addr_len); -extern int raw_read(struct sock *sk, unsigned char *buff, - int len, int noblock, unsigned flags); -extern int raw_rcv(struct sock *, struct sk_buff *, struct device *, - long, long); - -#endif /* _RAW_H */ diff --git a/pfinet/linux-inet/route.c b/pfinet/linux-inet/route.c deleted file mode 100644 index ce06dcfe..00000000 --- a/pfinet/linux-inet/route.c +++ /dev/null @@ -1,684 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * ROUTE - implementation of the IP router. - * - * Version: @(#)route.c 1.0.14 05/31/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Alan Cox, - * Linus Torvalds, - * - * Fixes: - * Alan Cox : Verify area fixes. - * Alan Cox : cli() protects routing changes - * Rui Oliveira : ICMP routing table updates - * (rco@di.uminho.pt) Routing table insertion and update - * Linus Torvalds : Rewrote bits to be sensible - * Alan Cox : Added BSD route gw semantics - * Alan Cox : Super /proc >4K - * Alan Cox : MTU in route table - * Alan Cox : MSS actually. Also added the window - * clamper. - * Sam Lantinga : Fixed route matching in rt_del() - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include "route.h" -#include "tcp.h" -#include -#include "sock.h" -#include "icmp.h" - -/* - * The routing table list - */ - -static struct rtable *rt_base = NULL; - -/* - * Pointer to the loopback route - */ - -static struct rtable *rt_loopback = NULL; - -/* - * Remove a routing table entry. - */ - -static void rt_del(unsigned long dst, char *devname) -{ - struct rtable *r, **rp; - unsigned long flags; - - rp = &rt_base; - - /* - * This must be done with interrupts off because we could take - * an ICMP_REDIRECT. - */ - - save_flags(flags); - cli(); - while((r = *rp) != NULL) - { - /* Make sure both the destination and the device match */ - if ( r->rt_dst != dst || - (devname != NULL && strcmp((r->rt_dev)->name,devname) != 0) ) - { - rp = &r->rt_next; - continue; - } - *rp = r->rt_next; - - /* - * If we delete the loopback route update its pointer. - */ - - if (rt_loopback == r) - rt_loopback = NULL; - kfree_s(r, sizeof(struct rtable)); - } - restore_flags(flags); -} - - -/* - * Remove all routing table entries for a device. This is called when - * a device is downed. - */ - -void ip_rt_flush(struct device *dev) -{ - struct rtable *r; - struct rtable **rp; - unsigned long flags; - - rp = &rt_base; - save_flags(flags); - cli(); - while ((r = *rp) != NULL) { - if (r->rt_dev != dev) { - rp = &r->rt_next; - continue; - } - *rp = r->rt_next; - if (rt_loopback == r) - rt_loopback = NULL; - kfree_s(r, sizeof(struct rtable)); - } - restore_flags(flags); -} - -/* - * Used by 'rt_add()' when we can't get the netmask any other way.. - * - * If the lower byte or two are zero, we guess the mask based on the - * number of zero 8-bit net numbers, otherwise we use the "default" - * masks judging by the destination address and our device netmask. - */ - -static inline unsigned long default_mask(unsigned long dst) -{ - dst = ntohl(dst); - if (IN_CLASSA(dst)) - return htonl(IN_CLASSA_NET); - if (IN_CLASSB(dst)) - return htonl(IN_CLASSB_NET); - return htonl(IN_CLASSC_NET); -} - - -/* - * If no mask is specified then generate a default entry. - */ - -static unsigned long guess_mask(unsigned long dst, struct device * dev) -{ - unsigned long mask; - - if (!dst) - return 0; - mask = default_mask(dst); - if ((dst ^ dev->pa_addr) & mask) - return mask; - return dev->pa_mask; -} - - -/* - * Find the route entry through which our gateway will be reached - */ - -static inline struct device * get_gw_dev(unsigned long gw) -{ - struct rtable * rt; - - for (rt = rt_base ; ; rt = rt->rt_next) - { - if (!rt) - return NULL; - if ((gw ^ rt->rt_dst) & rt->rt_mask) - continue; - /* - * Gateways behind gateways are a no-no - */ - - if (rt->rt_flags & RTF_GATEWAY) - return NULL; - return rt->rt_dev; - } -} - -/* - * Rewrote rt_add(), as the old one was weird - Linus - * - * This routine is used to update the IP routing table, either - * from the kernel (ICMP_REDIRECT) or via an ioctl call issued - * by the superuser. - */ - -void ip_rt_add(short flags, unsigned long dst, unsigned long mask, - unsigned long gw, struct device *dev, unsigned short mtu, unsigned long window) -{ - struct rtable *r, *rt; - struct rtable **rp; - unsigned long cpuflags; - - /* - * A host is a unique machine and has no network bits. - */ - - if (flags & RTF_HOST) - { - mask = 0xffffffff; - } - - /* - * Calculate the network mask - */ - - else if (!mask) - { - if (!((dst ^ dev->pa_addr) & dev->pa_mask)) - { - mask = dev->pa_mask; - flags &= ~RTF_GATEWAY; - if (flags & RTF_DYNAMIC) - { - /*printk("Dynamic route to my own net rejected\n");*/ - return; - } - } - else - mask = guess_mask(dst, dev); - dst &= mask; - } - - /* - * A gateway must be reachable and not a local address - */ - - if (gw == dev->pa_addr) - flags &= ~RTF_GATEWAY; - - if (flags & RTF_GATEWAY) - { - /* - * Don't try to add a gateway we can't reach.. - */ - - if (dev != get_gw_dev(gw)) - return; - - flags |= RTF_GATEWAY; - } - else - gw = 0; - - /* - * Allocate an entry and fill it in. - */ - - rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC); - if (rt == NULL) - { - return; - } - memset(rt, 0, sizeof(struct rtable)); - rt->rt_flags = flags | RTF_UP; - rt->rt_dst = dst; - rt->rt_dev = dev; - rt->rt_gateway = gw; - rt->rt_mask = mask; - rt->rt_mss = dev->mtu - HEADER_SIZE; - rt->rt_window = 0; /* Default is no clamping */ - - /* Are the MSS/Window valid ? */ - - if(rt->rt_flags & RTF_MSS) - rt->rt_mss = mtu; - - if(rt->rt_flags & RTF_WINDOW) - rt->rt_window = window; - - /* - * What we have to do is loop though this until we have - * found the first address which has a higher generality than - * the one in rt. Then we can put rt in right before it. - * The interrupts must be off for this process. - */ - - save_flags(cpuflags); - cli(); - - /* - * Remove old route if we are getting a duplicate. - */ - - rp = &rt_base; - while ((r = *rp) != NULL) - { - if (r->rt_dst != dst || - r->rt_mask != mask) - { - rp = &r->rt_next; - continue; - } - *rp = r->rt_next; - if (rt_loopback == r) - rt_loopback = NULL; - kfree_s(r, sizeof(struct rtable)); - } - - /* - * Add the new route - */ - - rp = &rt_base; - while ((r = *rp) != NULL) { - if ((r->rt_mask & mask) != mask) - break; - rp = &r->rt_next; - } - rt->rt_next = r; - *rp = rt; - - /* - * Update the loopback route - */ - - if ((rt->rt_dev->flags & IFF_LOOPBACK) && !rt_loopback) - rt_loopback = rt; - - /* - * Restore the interrupts and return - */ - - restore_flags(cpuflags); - return; -} - -/* - * Remove a routing table entry (exported version). - */ -void ip_rt_del (unsigned long dst, struct device *dev) -{ - /* Should probably just copy contents of rt_del and replace name - comparison with device comparsion. */ - rt_del (dst, dev->name); -} - - -/* - * Check if a mask is acceptable. - */ - -static inline int bad_mask(unsigned long mask, unsigned long addr) -{ - if (addr & (mask = ~mask)) - return 1; - mask = ntohl(mask); - if (mask & (mask+1)) - return 1; - return 0; -} - -/* - * Process a route add request from the user - */ - -static int rt_new(struct rtentry *r) -{ - int err; - char * devname; - struct device * dev = NULL; - unsigned long flags, daddr, mask, gw; - - /* - * If a device is specified find it. - */ - - if ((devname = r->rt_dev) != NULL) - { - err = getname(devname, &devname); - if (err) - return err; - dev = dev_get(devname); - putname(devname); - if (!dev) - return -EINVAL; - } - - /* - * If the device isn't INET, don't allow it - */ - - if (r->rt_dst.sa_family != AF_INET) - return -EAFNOSUPPORT; - - /* - * Make local copies of the important bits - */ - - flags = r->rt_flags; - daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr; - mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr; - gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr; - - - /* - * BSD emulation: Permits route add someroute gw one-of-my-addresses - * to indicate which iface. Not as clean as the nice Linux dev technique - * but people keep using it... - */ - - if (!dev && (flags & RTF_GATEWAY)) - { - struct device *dev2; - for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) - { - if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) - { - flags &= ~RTF_GATEWAY; - dev = dev2; - break; - } - } - } - - /* - * Ignore faulty masks - */ - - if (bad_mask(mask, daddr)) - mask = 0; - - /* - * Set the mask to nothing for host routes. - */ - - if (flags & RTF_HOST) - mask = 0xffffffff; - else if (mask && r->rt_genmask.sa_family != AF_INET) - return -EAFNOSUPPORT; - - /* - * You can only gateway IP via IP.. - */ - - if (flags & RTF_GATEWAY) - { - if (r->rt_gateway.sa_family != AF_INET) - return -EAFNOSUPPORT; - if (!dev) - dev = get_gw_dev(gw); - } - else if (!dev) - dev = ip_dev_check(daddr); - - /* - * Unknown device. - */ - - if (dev == NULL) - return -ENETUNREACH; - - /* - * Add the route - */ - - ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mss, r->rt_window); - return 0; -} - - -/* - * Remove a route, as requested by the user. - */ - -static int rt_kill(struct rtentry *r) -{ - struct sockaddr_in *trg; - char *devname; - int err; - - trg = (struct sockaddr_in *) &r->rt_dst; - if ((devname = r->rt_dev) != NULL) - { - err = getname(devname, &devname); - if (err) - return err; - } - rt_del(trg->sin_addr.s_addr, devname); - if ( devname != NULL ) - putname(devname); - return 0; -} - - -/* - * Called from the PROCfs module. This outputs /proc/net/route. - */ - -int rt_get_info(char *buffer, char **start, off_t offset, int length) -{ - struct rtable *r; - int len=0; - off_t pos=0; - off_t begin=0; - int size; - - len += sprintf(buffer, - "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\n"); - pos=len; - - /* - * This isn't quite right -- r->rt_dst is a struct! - */ - - for (r = rt_base; r != NULL; r = r->rt_next) - { - size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\n", - r->rt_dev->name, r->rt_dst, r->rt_gateway, - r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric, - r->rt_mask, (int)r->rt_mss, r->rt_window); - len+=size; - pos+=size; - if(posoffset+length) - break; - } - - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - -/* - * This is hackish, but results in better code. Use "-S" to see why. - */ - -#define early_out ({ goto no_route; 1; }) - -/* - * Route a packet. This needs to be fairly quick. Florian & Co. - * suggested a unified ARP and IP routing cache. Done right its - * probably a brilliant idea. I'd actually suggest a unified - * ARP/IP routing/Socket pointer cache. Volunteers welcome - */ - -struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr) -{ - struct rtable *rt; - - for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) - { - if (!((rt->rt_dst ^ daddr) & rt->rt_mask)) - break; - /* - * broadcast addresses can be special cases.. - */ - if (rt->rt_flags & RTF_GATEWAY) - continue; - if ((rt->rt_dev->flags & IFF_BROADCAST) && - (rt->rt_dev->pa_brdaddr == daddr)) - break; - } - - if(src_addr!=NULL) - *src_addr= rt->rt_dev->pa_addr; - - if (daddr == rt->rt_dev->pa_addr) { - if ((rt = rt_loopback) == NULL) - goto no_route; - } - rt->rt_use++; - return rt; -no_route: - return NULL; -} - -struct rtable * ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr) -{ - struct rtable *rt; - - for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) - { - /* - * No routed addressing. - */ - if (rt->rt_flags&RTF_GATEWAY) - continue; - - if (!((rt->rt_dst ^ daddr) & rt->rt_mask)) - break; - /* - * broadcast addresses can be special cases.. - */ - - if ((rt->rt_dev->flags & IFF_BROADCAST) && - rt->rt_dev->pa_brdaddr == daddr) - break; - } - - if(src_addr!=NULL) - *src_addr= rt->rt_dev->pa_addr; - - if (daddr == rt->rt_dev->pa_addr) { - if ((rt = rt_loopback) == NULL) - goto no_route; - } - rt->rt_use++; - return rt; -no_route: - return NULL; -} - -/* - * Backwards compatibility - */ - -static int ip_get_old_rtent(struct old_rtentry * src, struct rtentry * rt) -{ - int err; - struct old_rtentry tmp; - - err=verify_area(VERIFY_READ, src, sizeof(*src)); - if (err) - return err; - memcpy_fromfs(&tmp, src, sizeof(*src)); - memset(rt, 0, sizeof(*rt)); - rt->rt_dst = tmp.rt_dst; - rt->rt_gateway = tmp.rt_gateway; - rt->rt_genmask.sa_family = AF_INET; - ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask; - rt->rt_flags = tmp.rt_flags; - rt->rt_dev = tmp.rt_dev; - printk("Warning: obsolete routing request made.\n"); - return 0; -} - -#ifndef _HURD_ -/* - * Handle IP routing ioctl calls. These are used to manipulate the routing tables - */ - -int ip_rt_ioctl(unsigned int cmd, void *arg) -{ - int err; - struct rtentry rt; - - switch(cmd) - { - case SIOCADDRTOLD: /* Old style add route */ - case SIOCDELRTOLD: /* Old style delete route */ - if (!suser()) - return -EPERM; - err = ip_get_old_rtent((struct old_rtentry *) arg, &rt); - if (err) - return err; - return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt); - - case SIOCADDRT: /* Add a route */ - case SIOCDELRT: /* Delete a route */ - if (!suser()) - return -EPERM; - err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry)); - if (err) - return err; - memcpy_fromfs(&rt, arg, sizeof(struct rtentry)); - return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt); - } - - return -EINVAL; -} -#endif diff --git a/pfinet/linux-inet/route.h b/pfinet/linux-inet/route.h deleted file mode 100644 index e43efa4e..00000000 --- a/pfinet/linux-inet/route.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP router. - * - * Version: @(#)route.h 1.0.4 05/27/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Fixes: - * Alan Cox : Reformatted. Added ip_rt_local() - * Alan Cox : Support for TCP parameters. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _ROUTE_H -#define _ROUTE_H - - -#include - - -/* This is an entry in the IP routing table. */ -struct rtable -{ - struct rtable *rt_next; - unsigned long rt_dst; - unsigned long rt_mask; - unsigned long rt_gateway; - unsigned char rt_flags; - unsigned char rt_metric; - short rt_refcnt; - unsigned long rt_use; - unsigned short rt_mss; - unsigned long rt_window; - struct device *rt_dev; -}; - - -extern void ip_rt_flush(struct device *dev); -extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask, - unsigned long gw, struct device *dev, unsigned short mss, unsigned long window); -extern void ip_rt_del(unsigned long dst, struct device *dev); -extern struct rtable *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr); -extern struct rtable *ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr); -extern int rt_get_info(char * buffer, char **start, off_t offset, int length); -extern int ip_rt_ioctl(unsigned int cmd, void *arg); - -#endif /* _ROUTE_H */ diff --git a/pfinet/linux-inet/skbuff.c b/pfinet/linux-inet/skbuff.c deleted file mode 100644 index e4e1d247..00000000 --- a/pfinet/linux-inet/skbuff.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Routines having to do with the 'struct sk_buff' memory handlers. - * - * Authors: Alan Cox - * Florian La Roche - * - * Fixes: - * Alan Cox : Fixed the worst of the load balancer bugs. - * Dave Platt : Interrupt stacking fix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Note: There are a load of cli()/sti() pairs protecting the net_memory type - * variables. Without them for some reason the ++/-- operators do not come out - * atomic. Also with gcc 2.4.5 these counts can come out wrong anyway - use 2.5.8!! - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include -#include "route.h" -#include "tcp.h" -#include "udp.h" -#include -#include "sock.h" - - -/* - * Resource tracking variables - */ - -volatile unsigned long net_memory = 0; -volatile unsigned long net_skbcount = 0; -volatile unsigned long net_locked = 0; -volatile unsigned long net_allocs = 0; -volatile unsigned long net_fails = 0; -volatile unsigned long net_free_locked = 0; - -void show_net_buffers(void) -{ - printk("Networking buffers in use : %lu\n",net_skbcount); - printk("Memory committed to network buffers: %lu\n",net_memory); - printk("Network buffers locked by drivers : %lu\n",net_locked); - printk("Total network buffer allocations : %lu\n",net_allocs); - printk("Total failed network buffer allocs : %lu\n",net_fails); - printk("Total free while locked events : %lu\n",net_free_locked); -} - -#if CONFIG_SKB_CHECK - -/* - * Debugging paranoia. Can go later when this crud stack works - */ - -int skb_check(struct sk_buff *skb, int head, int line, char *file) -{ - if (head) { - if (skb->magic_debug_cookie != SK_HEAD_SKB) { - printk("File: %s Line %d, found a bad skb-head\n", - file,line); - return -1; - } - if (!skb->next || !skb->prev) { - printk("skb_check: head without next or prev\n"); - return -1; - } - if (skb->next->magic_debug_cookie != SK_HEAD_SKB - && skb->next->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad next head-skb member\n", - file,line); - return -1; - } - if (skb->prev->magic_debug_cookie != SK_HEAD_SKB - && skb->prev->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad prev head-skb member\n", - file,line); - return -1; - } -#if 0 - { - struct sk_buff *skb2 = skb->next; - int i = 0; - while (skb2 != skb && i < 5) { - if (skb_check(skb2, 0, line, file) < 0) { - printk("bad queue element in whole queue\n"); - return -1; - } - i++; - skb2 = skb2->next; - } - } -#endif - return 0; - } - if (skb->next != NULL && skb->next->magic_debug_cookie != SK_HEAD_SKB - && skb->next->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad next skb member\n", - file,line); - return -1; - } - if (skb->prev != NULL && skb->prev->magic_debug_cookie != SK_HEAD_SKB - && skb->prev->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad prev skb member\n", - file,line); - return -1; - } - - - if(skb->magic_debug_cookie==SK_FREED_SKB) - { - printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n", - file,line); - printk("skb=%p, real size=%ld, claimed size=%ld, free=%d\n", - skb,skb->truesize,skb->mem_len,skb->free); - return -1; - } - if(skb->magic_debug_cookie!=SK_GOOD_SKB) - { - printk("File: %s Line %d, passed a non skb!\n", file,line); - printk("skb=%p, real size=%ld, claimed size=%ld, free=%d\n", - skb,skb->truesize,skb->mem_len,skb->free); - return -1; - } - if(skb->mem_len!=skb->truesize) - { - printk("File: %s Line %d, Dubious size setting!\n",file,line); - printk("skb=%p, real size=%ld, claimed size=%ld\n", - skb,skb->truesize,skb->mem_len); - return -1; - } - /* Guess it might be acceptable then */ - return 0; -} -#endif - - -#ifdef CONFIG_SKB_CHECK -void skb_queue_head_init(struct sk_buff_head *list) -{ - list->prev = (struct sk_buff *)list; - list->next = (struct sk_buff *)list; - list->magic_debug_cookie = SK_HEAD_SKB; -} - - -/* - * Insert an sk_buff at the start of a list. - */ -void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk) -{ - unsigned long flags; - struct sk_buff *list = (struct sk_buff *)list_; - - save_flags(flags); - cli(); - - IS_SKB(newsk); - IS_SKB_HEAD(list); - if (newsk->next || newsk->prev) - printk("Suspicious queue head: sk_buff on list!\n"); - - newsk->next = list->next; - newsk->prev = list; - - newsk->next->prev = newsk; - newsk->prev->next = newsk; - - restore_flags(flags); -} - -/* - * Insert an sk_buff at the end of a list. - */ -void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk) -{ - unsigned long flags; - struct sk_buff *list = (struct sk_buff *)list_; - - save_flags(flags); - cli(); - - if (newsk->next || newsk->prev) - printk("Suspicious queue tail: sk_buff on list!\n"); - IS_SKB(newsk); - IS_SKB_HEAD(list); - - newsk->next = list; - newsk->prev = list->prev; - - newsk->next->prev = newsk; - newsk->prev->next = newsk; - - restore_flags(flags); -} - -/* - * Remove an sk_buff from a list. This routine is also interrupt safe - * so you can grab read and free buffers as another process adds them. - */ - -struct sk_buff *skb_dequeue(struct sk_buff_head *list_) -{ - long flags; - struct sk_buff *result; - struct sk_buff *list = (struct sk_buff *)list_; - - save_flags(flags); - cli(); - - IS_SKB_HEAD(list); - - result = list->next; - if (result == list) { - restore_flags(flags); - return NULL; - } - - result->next->prev = list; - list->next = result->next; - - result->next = NULL; - result->prev = NULL; - - restore_flags(flags); - - IS_SKB(result); - return result; -} - -/* - * Insert a packet before another one in a list. - */ -void skb_insert(struct sk_buff *old, struct sk_buff *newsk) -{ - unsigned long flags; - - IS_SKB(old); - IS_SKB(newsk); - - if(!old->next || !old->prev) - printk("insert before unlisted item!\n"); - if(newsk->next || newsk->prev) - printk("inserted item is already on a list.\n"); - - save_flags(flags); - cli(); - newsk->next = old; - newsk->prev = old->prev; - old->prev = newsk; - newsk->prev->next = newsk; - - restore_flags(flags); -} - -/* - * Place a packet after a given packet in a list. - */ -void skb_append(struct sk_buff *old, struct sk_buff *newsk) -{ - unsigned long flags; - - IS_SKB(old); - IS_SKB(newsk); - - if(!old->next || !old->prev) - printk("append before unlisted item!\n"); - if(newsk->next || newsk->prev) - printk("append item is already on a list.\n"); - - save_flags(flags); - cli(); - - newsk->prev = old; - newsk->next = old->next; - newsk->next->prev = newsk; - old->next = newsk; - - restore_flags(flags); -} - -/* - * Remove an sk_buff from its list. Works even without knowing the list it - * is sitting on, which can be handy at times. It also means that THE LIST - * MUST EXIST when you unlink. Thus a list must have its contents unlinked - * _FIRST_. - */ -void skb_unlink(struct sk_buff *skb) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - IS_SKB(skb); - - if(skb->prev && skb->next) - { - skb->next->prev = skb->prev; - skb->prev->next = skb->next; - skb->next = NULL; - skb->prev = NULL; - } -#ifdef PARANOID_BUGHUNT_MODE /* This is legal but we sometimes want to watch it */ - else - printk("skb_unlink: not a linked element\n"); -#endif - restore_flags(flags); -} - -#endif - -/* - * Free an sk_buff. This still knows about things it should - * not need to like protocols and sockets. - */ - -void kfree_skb(struct sk_buff *skb, int rw) -{ - if (skb == NULL) - { - printk("kfree_skb: skb = NULL (from %p)\n", - __builtin_return_address(0)); - return; - } -#ifdef CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - if (skb->lock) - { - skb->free = 3; /* Free when unlocked */ - net_free_locked++; - return; - } - if (skb->free == 2) - printk("Warning: kfree_skb passed an skb that nobody set the free flag on! (from %p)\n", - __builtin_return_address(0)); - if (skb->next) - printk("Warning: kfree_skb passed an skb still on a list (from %p).\n", - __builtin_return_address(0)); - if (skb->sk) - { - if(skb->sk->prot!=NULL) - { - if (rw) - skb->sk->prot->rfree(skb->sk, skb, skb->mem_len); - else - skb->sk->prot->wfree(skb->sk, skb, skb->mem_len); - - } - else - { - unsigned long flags; - /* Non INET - default wmalloc/rmalloc handler */ - save_flags(flags); - cli(); - if (rw) - skb->sk->rmem_alloc-=skb->mem_len; - else - skb->sk->wmem_alloc-=skb->mem_len; - restore_flags(flags); - if(!skb->sk->dead) - skb->sk->write_space(skb->sk); - kfree_skbmem(skb,skb->mem_len); - } - } - else - kfree_skbmem(skb, skb->mem_len); -} - -/* - * Allocate a new skbuff. We do this ourselves so we can fill in a few 'private' - * fields and also do memory statistics to find all the [BEEP] leaks. - */ -struct sk_buff *alloc_skb(unsigned int size,int priority) -{ - struct sk_buff *skb; - unsigned long flags; - - if (intr_count && priority!=GFP_ATOMIC) { - static int count = 0; - if (++count < 5) { - printk("alloc_skb called nonatomically from interrupt %p\n", - __builtin_return_address(0)); - priority = GFP_ATOMIC; - } - } - - size+=sizeof(struct sk_buff); - skb=(struct sk_buff *)kmalloc(size,priority); - if (skb == NULL) - { - net_fails++; - return NULL; - } -#ifdef PARANOID_BUGHUNT_MODE - if(skb->magic_debug_cookie == SK_GOOD_SKB) - printk("Kernel kmalloc handed us an existing skb (%p)\n",skb); -#endif - - net_allocs++; - - skb->free = 2; /* Invalid so we pick up forgetful users */ - skb->lock = 0; - skb->pkt_type = PACKET_HOST; /* Default type */ - skb->truesize = size; - skb->mem_len = size; - skb->mem_addr = skb; -#ifdef CONFIG_SLAVE_BALANCING - skb->in_dev_queue = 0; -#endif - skb->fraglist = NULL; - skb->prev = skb->next = NULL; - skb->link3 = NULL; - skb->sk = NULL; - skb->localroute=0; - skb->stamp.tv_sec=0; /* No idea about time */ - skb->localroute = 0; - save_flags(flags); - cli(); - net_memory += size; - net_skbcount++; - restore_flags(flags); -#if CONFIG_SKB_CHECK - skb->magic_debug_cookie = SK_GOOD_SKB; -#endif - skb->users = 0; - return skb; -} - -/* - * Free an skbuff by memory - */ - -void kfree_skbmem(struct sk_buff *skb,unsigned size) -{ - unsigned long flags; -#ifdef CONFIG_SLAVE_BALANCING - save_flags(flags); - cli(); - if(skb->in_dev_queue && skb->dev!=NULL) - skb->dev->pkt_queue--; - restore_flags(flags); -#endif -#ifdef CONFIG_SKB_CHECK - IS_SKB(skb); - if(size!=skb->truesize) - printk("kfree_skbmem: size mismatch.\n"); - - if(skb->magic_debug_cookie == SK_GOOD_SKB) - { - save_flags(flags); - cli(); - IS_SKB(skb); - skb->magic_debug_cookie = SK_FREED_SKB; - kfree_s((void *)skb,size); - net_skbcount--; - net_memory -= size; - restore_flags(flags); - } - else - printk("kfree_skbmem: bad magic cookie\n"); -#else - save_flags(flags); - cli(); - kfree_s((void *)skb,size); - net_skbcount--; - net_memory -= size; - restore_flags(flags); -#endif -} - -/* - * Duplicate an sk_buff. The new one is not owned by a socket or locked - * and will be freed on deletion. - */ - -struct sk_buff *skb_clone(struct sk_buff *skb, int priority) -{ - struct sk_buff *n; - unsigned long offset; - - n=alloc_skb(skb->mem_len-sizeof(struct sk_buff),priority); - if(n==NULL) - return NULL; - - offset=((char *)n)-((char *)skb); - - memcpy(n->data,skb->data,skb->mem_len-sizeof(struct sk_buff)); - n->len=skb->len; - n->link3=NULL; - n->sk=NULL; - n->when=skb->when; - n->dev=skb->dev; - n->h.raw=skb->h.raw+offset; - n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset); - n->fraglen=skb->fraglen; - n->fraglist=skb->fraglist; - n->saddr=skb->saddr; - n->daddr=skb->daddr; - n->raddr=skb->raddr; - n->acked=skb->acked; - n->used=skb->used; - n->free=1; - n->arp=skb->arp; - n->tries=0; - n->lock=0; - n->users=0; - n->pkt_type=skb->pkt_type; - return n; -} - - -/* - * Skbuff device locking - */ - -void skb_device_lock(struct sk_buff *skb) -{ - if(skb->lock) - printk("double lock on device queue!\n"); - else - net_locked++; - skb->lock++; -} - -void skb_device_unlock(struct sk_buff *skb) -{ - if(skb->lock==0) - printk("double unlock on device queue!\n"); - skb->lock--; - if(skb->lock==0) - net_locked--; -} - -void dev_kfree_skb(struct sk_buff *skb, int mode) -{ - unsigned long flags; - - save_flags(flags); - cli(); - if(skb->lock==1) - net_locked--; - - if (!--skb->lock && (skb->free == 1 || skb->free == 3)) - { - restore_flags(flags); - kfree_skb(skb,mode); - } - else - restore_flags(flags); -} - -int skb_device_locked(struct sk_buff *skb) -{ - return skb->lock? 1 : 0; -} - diff --git a/pfinet/linux-inet/snmp.h b/pfinet/linux-inet/snmp.h deleted file mode 100644 index 552292be..00000000 --- a/pfinet/linux-inet/snmp.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * SNMP MIB entries for the IP subsystem. - * - * Alan Cox - * - * We don't chose to implement SNMP in the kernel (this would - * be silly as SNMP is a pain in the backside in places). We do - * however need to collect the MIB statistics and export them - * out of /proc (eventually) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#ifndef _SNMP_H -#define _SNMP_H - -/* - * We use all unsigned longs. Linux will soon be so reliable that even these - * will rapidly get too small 8-). Seriously consider the IpInReceives count - * on the 20Gb/s + networks people expect in a few years time! - */ - -struct ip_mib -{ - unsigned long IpForwarding; - unsigned long IpDefaultTTL; - unsigned long IpInReceives; - unsigned long IpInHdrErrors; - unsigned long IpInAddrErrors; - unsigned long IpForwDatagrams; - unsigned long IpInUnknownProtos; - unsigned long IpInDiscards; - unsigned long IpInDelivers; - unsigned long IpOutRequests; - unsigned long IpOutDiscards; - unsigned long IpOutNoRoutes; - unsigned long IpReasmTimeout; - unsigned long IpReasmReqds; - unsigned long IpReasmOKs; - unsigned long IpReasmFails; - unsigned long IpFragOKs; - unsigned long IpFragFails; - unsigned long IpFragCreates; -}; - - -struct icmp_mib -{ - unsigned long IcmpInMsgs; - unsigned long IcmpInErrors; - unsigned long IcmpInDestUnreachs; - unsigned long IcmpInTimeExcds; - unsigned long IcmpInParmProbs; - unsigned long IcmpInSrcQuenchs; - unsigned long IcmpInRedirects; - unsigned long IcmpInEchos; - unsigned long IcmpInEchoReps; - unsigned long IcmpInTimestamps; - unsigned long IcmpInTimestampReps; - unsigned long IcmpInAddrMasks; - unsigned long IcmpInAddrMaskReps; - unsigned long IcmpOutMsgs; - unsigned long IcmpOutErrors; - unsigned long IcmpOutDestUnreachs; - unsigned long IcmpOutTimeExcds; - unsigned long IcmpOutParmProbs; - unsigned long IcmpOutSrcQuenchs; - unsigned long IcmpOutRedirects; - unsigned long IcmpOutEchos; - unsigned long IcmpOutEchoReps; - unsigned long IcmpOutTimestamps; - unsigned long IcmpOutTimestampReps; - unsigned long IcmpOutAddrMasks; - unsigned long IcmpOutAddrMaskReps; -}; - -struct tcp_mib -{ - unsigned long TcpRtoAlgorithm; - unsigned long TcpRtoMin; - unsigned long TcpRtoMax; - unsigned long TcpMaxConn; - unsigned long TcpActiveOpens; - unsigned long TcpPassiveOpens; - unsigned long TcpAttemptFails; - unsigned long TcpEstabResets; - unsigned long TcpCurrEstab; - unsigned long TcpInSegs; - unsigned long TcpOutSegs; - unsigned long TcpRetransSegs; -}; - -struct udp_mib -{ - unsigned long UdpInDatagrams; - unsigned long UdpNoPorts; - unsigned long UdpInErrors; - unsigned long UdpOutDatagrams; -}; - - -#endif diff --git a/pfinet/linux-inet/sock.c b/pfinet/linux-inet/sock.c deleted file mode 100644 index 40d4a8f4..00000000 --- a/pfinet/linux-inet/sock.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic socket support routines. Memory allocators, sk->inuse/release - * handler for protocols to use and generic option handler. - * - * - * Version: @(#)sock.c 1.0.17 06/02/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Florian La Roche, - * Alan Cox, - * - * Fixes: - * Alan Cox : Numerous verify_area() problems - * Alan Cox : Connecting on a connecting socket - * now returns an error for tcp. - * Alan Cox : sock->protocol is set correctly. - * and is not sometimes left as 0. - * Alan Cox : connect handles icmp errors on a - * connect properly. Unfortunately there - * is a restart syscall nasty there. I - * can't match BSD without hacking the C - * library. Ideas urgently sought! - * Alan Cox : Disallow bind() to addresses that are - * not ours - especially broadcast ones!! - * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost) - * Alan Cox : sock_wfree/sock_rfree don't destroy sockets, - * instead they leave that for the DESTROY timer. - * Alan Cox : Clean up error flag in accept - * Alan Cox : TCP ack handling is buggy, the DESTROY timer - * was buggy. Put a remove_sock() in the handler - * for memory when we hit 0. Also altered the timer - * code. The ACK stuff can wait and needs major - * TCP layer surgery. - * Alan Cox : Fixed TCP ack bug, removed remove sock - * and fixed timer/inet_bh race. - * Alan Cox : Added zapped flag for TCP - * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code - * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb - * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources - * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing. - * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so... - * Rick Sladkey : Relaxed UDP rules for matching packets. - * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support - * Pauline Middelink : identd support - * Alan Cox : Fixed connect() taking signals I think. - * Alan Cox : SO_LINGER supported - * Alan Cox : Error reporting fixes - * Anonymous : inet_create tidied up (sk->reuse setting) - * Alan Cox : inet sockets don't set sk->type! - * Alan Cox : Split socket option code - * Alan Cox : Callbacks - * Alan Cox : Nagle flag for Charles & Johannes stuff - * Alex : Removed restriction on inet fioctl - * Alan Cox : Splitting INET from NET core - * Alan Cox : Fixed bogus SO_TYPE handling in getsockopt() - * Adam Caldwell : Missing return in SO_DONTROUTE/SO_DEBUG code - * Alan Cox : Split IP from generic code - * Alan Cox : New kfree_skbmem() - * Alan Cox : Make SO_DEBUG superuser only. - * Alan Cox : Allow anyone to clear SO_DEBUG - * (compatibility fix) - * - * To Fix: - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include "ip.h" -#include "protocol.h" -#include "arp.h" -#include "rarp.h" -#include "route.h" -#include "tcp.h" -#include "udp.h" -#include -#include "sock.h" -#include "raw.h" -#include "icmp.h" - -#define min(a,b) ((a)<(b)?(a):(b)) - -/* - * This is meant for all protocols to use and covers goings on - * at the socket level. Everything here is generic. - */ - -int sock_setsockopt(struct sock *sk, int level, int optname, - char *optval, int optlen) -{ - int val; - int err; - struct linger ling; - - if (optval == NULL) - return(-EINVAL); - - err=verify_area(VERIFY_READ, optval, sizeof(int)); - if(err) - return err; - - val = get_fs_long((unsigned long *)optval); - switch(optname) - { - case SO_TYPE: - case SO_ERROR: - return(-ENOPROTOOPT); - - case SO_DEBUG: - if(val && !suser()) - return(-EPERM); - sk->debug=val?1:0; - return 0; - case SO_DONTROUTE: - sk->localroute=val?1:0; - return 0; - case SO_BROADCAST: - sk->broadcast=val?1:0; - return 0; - case SO_SNDBUF: - if(val>32767) - val=32767; - if(val<256) - val=256; - sk->sndbuf=val; - return 0; - case SO_LINGER: - err=verify_area(VERIFY_READ,optval,sizeof(ling)); - if(err) - return err; - memcpy_fromfs(&ling,optval,sizeof(ling)); - if(ling.l_onoff==0) - sk->linger=0; - else - { - sk->lingertime=ling.l_linger; - sk->linger=1; - } - return 0; - case SO_RCVBUF: - if(val>32767) - val=32767; - if(val<256) - val=256; - sk->rcvbuf=val; - return(0); - - case SO_REUSEADDR: - if (val) - sk->reuse = 1; - else - sk->reuse = 0; - return(0); - - case SO_KEEPALIVE: - if (val) - sk->keepopen = 1; - else - sk->keepopen = 0; - return(0); - - case SO_OOBINLINE: - if (val) - sk->urginline = 1; - else - sk->urginline = 0; - return(0); - - case SO_NO_CHECK: - if (val) - sk->no_check = 1; - else - sk->no_check = 0; - return(0); - - case SO_PRIORITY: - if (val >= 0 && val < DEV_NUMBUFFS) - { - sk->priority = val; - } - else - { - return(-EINVAL); - } - return(0); - - default: - return(-ENOPROTOOPT); - } -} - - -int sock_getsockopt(struct sock *sk, int level, int optname, - char *optval, int *optlen) -{ - int val; - int err; - struct linger ling; - - switch(optname) - { - case SO_DEBUG: - val = sk->debug; - break; - - case SO_DONTROUTE: - val = sk->localroute; - break; - - case SO_BROADCAST: - val= sk->broadcast; - break; - - case SO_LINGER: - err=verify_area(VERIFY_WRITE,optval,sizeof(ling)); - if(err) - return err; - err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); - if(err) - return err; - put_fs_long(sizeof(ling),(unsigned long *)optlen); - ling.l_onoff=sk->linger; - ling.l_linger=sk->lingertime; - memcpy_tofs(optval,&ling,sizeof(ling)); - return 0; - - case SO_SNDBUF: - val=sk->sndbuf; - break; - - case SO_RCVBUF: - val =sk->rcvbuf; - break; - - case SO_REUSEADDR: - val = sk->reuse; - break; - - case SO_KEEPALIVE: - val = sk->keepopen; - break; - - case SO_TYPE: -#if 0 - if (sk->prot == &tcp_prot) - val = SOCK_STREAM; - else - val = SOCK_DGRAM; -#endif - val = sk->type; - break; - - case SO_ERROR: - val = sk->err; - sk->err = 0; - break; - - case SO_OOBINLINE: - val = sk->urginline; - break; - - case SO_NO_CHECK: - val = sk->no_check; - break; - - case SO_PRIORITY: - val = sk->priority; - break; - - default: - return(-ENOPROTOOPT); - } - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; - put_fs_long(sizeof(int),(unsigned long *) optlen); - - err=verify_area(VERIFY_WRITE, optval, sizeof(int)); - if(err) - return err; - put_fs_long(val,(unsigned long *)optval); - - return(0); -} - - -struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority) -{ - if (sk) - { - if (sk->wmem_alloc + size < sk->sndbuf || force) - { - struct sk_buff * c = alloc_skb(size, priority); - if (c) - { - unsigned long flags; - save_flags(flags); - cli(); - sk->wmem_alloc+= c->mem_len; - restore_flags(flags); /* was sti(); */ - } - return c; - } - return(NULL); - } - return(alloc_skb(size, priority)); -} - - -struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority) -{ - if (sk) - { - if (sk->rmem_alloc + size < sk->rcvbuf || force) - { - struct sk_buff *c = alloc_skb(size, priority); - if (c) - { - unsigned long flags; - save_flags(flags); - cli(); - sk->rmem_alloc += c->mem_len; - restore_flags(flags); /* was sti(); */ - } - return(c); - } - return(NULL); - } - return(alloc_skb(size, priority)); -} - - -unsigned long sock_rspace(struct sock *sk) -{ - int amt; - - if (sk != NULL) - { - if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW) - return(0); - amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW); - if (amt < 0) - return(0); - return(amt); - } - return(0); -} - - -unsigned long sock_wspace(struct sock *sk) -{ - if (sk != NULL) - { - if (sk->shutdown & SEND_SHUTDOWN) - return(0); - if (sk->wmem_alloc >= sk->sndbuf) - return(0); - return(sk->sndbuf-sk->wmem_alloc ); - } - return(0); -} - - -void sock_wfree(struct sock *sk, struct sk_buff *skb, unsigned long size) -{ -#ifdef CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - kfree_skbmem(skb, size); - if (sk) - { - unsigned long flags; - save_flags(flags); - cli(); - sk->wmem_alloc -= size; - restore_flags(flags); - /* In case it might be waiting for more memory. */ - if (!sk->dead) - sk->write_space(sk); - return; - } -} - - -void sock_rfree(struct sock *sk, struct sk_buff *skb, unsigned long size) -{ -#ifdef CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - kfree_skbmem(skb, size); - if (sk) - { - unsigned long flags; - save_flags(flags); - cli(); - sk->rmem_alloc -= size; - restore_flags(flags); - } -} - -/* - * Generic send/receive buffer handlers - */ - -struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, int noblock, int *errcode) -{ - struct sk_buff *skb; - int err; - - sk->inuse=1; - - do - { - if(sk->err!=0) - { - cli(); - err= -sk->err; - sk->err=0; - sti(); - *errcode=err; - return NULL; - } - - if(sk->shutdown&SEND_SHUTDOWN) - { - *errcode=-EPIPE; - return NULL; - } - - skb = sock_wmalloc(sk, size, 0, GFP_KERNEL); - - if(skb==NULL) - { - unsigned long tmp; - - sk->socket->flags |= SO_NOSPACE; - if(noblock) - { - *errcode=-EAGAIN; - return NULL; - } - if(sk->shutdown&SEND_SHUTDOWN) - { - *errcode=-EPIPE; - return NULL; - } - tmp = sk->wmem_alloc; - cli(); - if(sk->shutdown&SEND_SHUTDOWN) - { - sti(); - *errcode=-EPIPE; - return NULL; - } - - if( tmp <= sk->wmem_alloc) - { - sk->socket->flags &= ~SO_NOSPACE; - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) - { - sti(); - *errcode = -ERESTARTSYS; - return NULL; - } - } - sti(); - } - } - while(skb==NULL); - - return skb; -} - -/* - * Queue a received datagram if it will fit. Stream and sequenced protocols - * can't normally use this as they need to fit buffers in and play with them. - */ - -int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - unsigned long flags; - if(sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) - return -ENOMEM; - save_flags(flags); - cli(); - sk->rmem_alloc+=skb->mem_len; - skb->sk=sk; - restore_flags(flags); - skb_queue_tail(&sk->receive_queue,skb); - if(!sk->dead) - sk->data_ready(sk,skb->len); - return 0; -} - -void release_sock(struct sock *sk) -{ - unsigned long flags; -#ifdef CONFIG_INET - struct sk_buff *skb; -#endif - - if (!sk->prot) - return; - /* - * Make the backlog atomic. If we don't do this there is a tiny - * window where a packet may arrive between the sk->blog being - * tested and then set with sk->inuse still 0 causing an extra - * unwanted re-entry into release_sock(). - */ - - save_flags(flags); - cli(); - if (sk->blog) - { - restore_flags(flags); - return; - } - sk->blog=1; - sk->inuse = 1; - restore_flags(flags); -#ifdef CONFIG_INET - /* See if we have any packets built up. */ - while((skb = skb_dequeue(&sk->back_log)) != NULL) - { - sk->blog = 1; - if (sk->prot->rcv) - sk->prot->rcv(skb, skb->dev, sk->opt, - skb->saddr, skb->len, skb->daddr, 1, - /* Only used for/by raw sockets. */ - (struct inet_protocol *)sk->pair); - } -#endif - sk->blog = 0; - sk->inuse = 0; -#ifdef CONFIG_INET - if (sk->dead && sk->state == TCP_CLOSE) - { - /* Should be about 2 rtt's */ - reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME)); - } -#endif -} - - diff --git a/pfinet/linux-inet/sock.h b/pfinet/linux-inet/sock.h deleted file mode 100644 index 2005745e..00000000 --- a/pfinet/linux-inet/sock.h +++ /dev/null @@ -1,316 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the AF_INET socket handler. - * - * Version: @(#)sock.h 1.0.4 05/13/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Corey Minyard - * Florian La Roche - * - * Fixes: - * Alan Cox : Volatiles in skbuff pointers. See - * skbuff comments. May be overdone, - * better to prove they can be removed - * than the reverse. - * Alan Cox : Added a zapped field for tcp to note - * a socket is reset and must stay shut up - * Alan Cox : New fields for options - * Pauline Middelink : identd support - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _SOCK_H -#define _SOCK_H - -#include -#include /* struct options */ -#include /* struct tcphdr */ -#include - -#include /* struct sk_buff */ -#include "protocol.h" /* struct inet_protocol */ -#ifdef CONFIG_AX25 -#include "ax25.h" -#endif -#ifdef CONFIG_IPX -#include "ipx.h" -#endif -#ifdef CONFIG_ATALK -#include -#endif - -#include - -#define SOCK_ARRAY_SIZE 256 /* Think big (also on some systems a byte is faster */ - - -/* - * This structure really needs to be cleaned up. - * Most of it is for TCP, and not used by any of - * the other protocols. - */ -struct sock { - struct options *opt; - volatile unsigned long wmem_alloc; - volatile unsigned long rmem_alloc; - unsigned long write_seq; - unsigned long sent_seq; - unsigned long acked_seq; - unsigned long copied_seq; - unsigned long rcv_ack_seq; - unsigned long window_seq; - unsigned long fin_seq; - unsigned long urg_seq; - unsigned long urg_data; - - /* - * Not all are volatile, but some are, so we - * might as well say they all are. - */ - volatile char inuse, - dead, - urginline, - intr, - blog, - done, - reuse, - keepopen, - linger, - delay_acks, - destroy, - ack_timed, - no_check, - zapped, /* In ax25 & ipx means not linked */ - broadcast, - nonagle; - unsigned long lingertime; - int proc; - struct sock *next; - struct sock *prev; /* Doubly linked chain.. */ - struct sock *pair; - struct sk_buff * volatile send_head; - struct sk_buff * volatile send_tail; - struct sk_buff_head back_log; - struct sk_buff *partial; - struct timer_list partial_timer; - long retransmits; - struct sk_buff_head write_queue, - receive_queue; - struct proto *prot; - struct wait_queue **sleep; - unsigned long daddr; - unsigned long saddr; - unsigned short max_unacked; - unsigned short window; - unsigned short bytes_rcv; -/* mss is min(mtu, max_window) */ - unsigned short mtu; /* mss negotiated in the syn's */ - volatile unsigned short mss; /* current eff. mss - can change */ - volatile unsigned short user_mss; /* mss requested by user in ioctl */ - volatile unsigned short max_window; - unsigned long window_clamp; - unsigned short num; - volatile unsigned short cong_window; - volatile unsigned short cong_count; - volatile unsigned short ssthresh; - volatile unsigned short packets_out; - volatile unsigned short shutdown; - volatile unsigned long rtt; - volatile unsigned long mdev; - volatile unsigned long rto; -/* currently backoff isn't used, but I'm maintaining it in case - * we want to go back to a backoff formula that needs it - */ - volatile unsigned short backoff; - volatile error_t err; /* Note change XXX HURD */ - unsigned char protocol; - volatile unsigned char state; - volatile unsigned char ack_backlog; - unsigned char max_ack_backlog; - unsigned char priority; - unsigned char debug; - unsigned short rcvbuf; - unsigned short sndbuf; - unsigned short type; - unsigned char localroute; /* Route locally only */ -#ifdef CONFIG_IPX - ipx_address ipx_dest_addr; - ipx_interface *ipx_intrfc; - unsigned short ipx_port; - unsigned short ipx_type; -#endif -#ifdef CONFIG_AX25 -/* Really we want to add a per protocol private area */ - ax25_address ax25_source_addr,ax25_dest_addr; - struct sk_buff *volatile ax25_retxq[8]; - char ax25_state,ax25_vs,ax25_vr,ax25_lastrxnr,ax25_lasttxnr; - char ax25_condition; - char ax25_retxcnt; - char ax25_xx; - char ax25_retxqi; - char ax25_rrtimer; - char ax25_timer; - unsigned char ax25_n2; - unsigned short ax25_t1,ax25_t2,ax25_t3; - ax25_digi *ax25_digipeat; -#endif -#ifdef CONFIG_ATALK - struct atalk_sock at; -#endif - -/* IP 'private area' or will be eventually */ - int ip_ttl; /* TTL setting */ - int ip_tos; /* TOS */ - struct tcphdr dummy_th; - struct timer_list keepalive_timer; /* TCP keepalive hack */ - struct timer_list retransmit_timer; /* TCP retransmit timer */ - struct timer_list ack_timer; /* TCP delayed ack timer */ - int ip_xmit_timeout; /* Why the timeout is running */ -#ifdef CONFIG_IP_MULTICAST - int ip_mc_ttl; /* Multicasting TTL */ - int ip_mc_loop; /* Loopback (not implemented yet) */ - char ip_mc_name[MAX_ADDR_LEN]; /* Multicast device name */ - struct ip_mc_socklist *ip_mc_list; /* Group array */ -#endif - - /* This part is used for the timeout functions (timer.c). */ - int timeout; /* What are we waiting for? */ - struct timer_list timer; /* This is the TIME_WAIT/receive timer when we are doing IP */ - struct timeval stamp; - - /* identd */ - struct socket *socket; - - /* Callbacks */ - void (*state_change)(struct sock *sk); - void (*data_ready)(struct sock *sk,int bytes); - void (*write_space)(struct sock *sk); - void (*error_report)(struct sock *sk); - -}; - -struct proto { - struct sk_buff * (*wmalloc)(struct sock *sk, - unsigned long size, int force, - int priority); - struct sk_buff * (*rmalloc)(struct sock *sk, - unsigned long size, int force, - int priority); - void (*wfree)(struct sock *sk, struct sk_buff *skb, - unsigned long size); - void (*rfree)(struct sock *sk, struct sk_buff *skb, - unsigned long size); - unsigned long (*rspace)(struct sock *sk); - unsigned long (*wspace)(struct sock *sk); - void (*close)(struct sock *sk, int timeout); - int (*read)(struct sock *sk, unsigned char *to, - int len, int nonblock, unsigned flags); - int (*write)(struct sock *sk, unsigned char *to, - int len, int nonblock, unsigned flags); - int (*sendto)(struct sock *sk, - unsigned char *from, int len, int noblock, - unsigned flags, struct sockaddr_in *usin, - int addr_len); - int (*recvfrom)(struct sock *sk, - unsigned char *from, int len, int noblock, - unsigned flags, struct sockaddr_in *usin, - int *addr_len); - int (*build_header)(struct sk_buff *skb, - unsigned long saddr, - unsigned long daddr, - struct device **dev, int type, - struct options *opt, int len, int tos, int ttl); - int (*connect)(struct sock *sk, - struct sockaddr_in *usin, int addr_len); - struct sock * (*accept) (struct sock *sk, int flags); - void (*queue_xmit)(struct sock *sk, - struct device *dev, struct sk_buff *skb, - int free); - void (*retransmit)(struct sock *sk, int all); - void (*write_wakeup)(struct sock *sk); - void (*read_wakeup)(struct sock *sk); - int (*rcv)(struct sk_buff *buff, struct device *dev, - struct options *opt, unsigned long daddr, - unsigned short len, unsigned long saddr, - int redo, struct inet_protocol *protocol); - int (*select)(struct sock *sk, int which, - select_table *wait); - int (*ioctl)(struct sock *sk, int cmd, - unsigned long arg); - int (*init)(struct sock *sk); - void (*shutdown)(struct sock *sk, int how); - int (*setsockopt)(struct sock *sk, int level, int optname, - char *optval, int optlen); - int (*getsockopt)(struct sock *sk, int level, int optname, - char *optval, int *option); - unsigned short max_header; - unsigned long retransmits; - struct sock * sock_array[SOCK_ARRAY_SIZE]; - char name[80]; - int inuse, highestinuse; -}; - -#define TIME_WRITE 1 -#define TIME_CLOSE 2 -#define TIME_KEEPOPEN 3 -#define TIME_DESTROY 4 -#define TIME_DONE 5 /* used to absorb those last few packets */ -#define TIME_PROBE0 6 -#define SOCK_DESTROY_TIME 1000 /* about 10 seconds */ - -#define PROT_SOCK 1024 /* Sockets 0-1023 can't be bound too unless you are superuser */ - -#define SHUTDOWN_MASK 3 -#define RCV_SHUTDOWN 1 -#define SEND_SHUTDOWN 2 - - -extern void destroy_sock(struct sock *sk); -extern unsigned short get_new_socknum(struct proto *, unsigned short); -extern void put_sock(unsigned short, struct sock *); -extern void release_sock(struct sock *sk); -extern struct sock *get_sock(struct proto *, unsigned short, - unsigned long, unsigned short, - unsigned long); -extern struct sock *get_sock_mcast(struct sock *, unsigned short, - unsigned long, unsigned short, - unsigned long); -extern struct sock *get_sock_raw(struct sock *, unsigned short, - unsigned long, unsigned long); - -extern struct sk_buff *sock_wmalloc(struct sock *sk, - unsigned long size, int force, - int priority); -extern struct sk_buff *sock_rmalloc(struct sock *sk, - unsigned long size, int force, - int priority); -extern void sock_wfree(struct sock *sk, struct sk_buff *skb, - unsigned long size); -extern void sock_rfree(struct sock *sk, struct sk_buff *skb, - unsigned long size); -extern unsigned long sock_rspace(struct sock *sk); -extern unsigned long sock_wspace(struct sock *sk); - -extern int sock_setsockopt(struct sock *sk,int level,int op,char *optval,int optlen); - -extern int sock_getsockopt(struct sock *sk,int level,int op,char *optval,int *optlen); -extern struct sk_buff *sock_alloc_send_skb(struct sock *skb, unsigned long size, int noblock, int *errcode); -extern int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); - -/* declarations from timer.c */ -extern struct sock *timer_base; - -void delete_timer (struct sock *); -void reset_timer (struct sock *, int, unsigned long); -void net_timer (unsigned long); - - -#endif /* _SOCK_H */ diff --git a/pfinet/linux-inet/tcp.c b/pfinet/linux-inet/tcp.c deleted file mode 100644 index 3005fbfd..00000000 --- a/pfinet/linux-inet/tcp.c +++ /dev/null @@ -1,5121 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Implementation of the Transmission Control Protocol(TCP). - * - * Version: @(#)tcp.c 1.0.16 05/25/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Mark Evans, - * Corey Minyard - * Florian La Roche, - * Charles Hedrick, - * Linus Torvalds, - * Alan Cox, - * Matthew Dillon, - * Arnt Gulbrandsen, - * - * Fixes: - * Alan Cox : Numerous verify_area() calls - * Alan Cox : Set the ACK bit on a reset - * Alan Cox : Stopped it crashing if it closed while sk->inuse=1 - * and was trying to connect (tcp_err()). - * Alan Cox : All icmp error handling was broken - * pointers passed where wrong and the - * socket was looked up backwards. Nobody - * tested any icmp error code obviously. - * Alan Cox : tcp_err() now handled properly. It wakes people - * on errors. select behaves and the icmp error race - * has gone by moving it into sock.c - * Alan Cox : tcp_reset() fixed to work for everything not just - * packets for unknown sockets. - * Alan Cox : tcp option processing. - * Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong] - * Herp Rosmanith : More reset fixes - * Alan Cox : No longer acks invalid rst frames. Acking - * any kind of RST is right out. - * Alan Cox : Sets an ignore me flag on an rst receive - * otherwise odd bits of prattle escape still - * Alan Cox : Fixed another acking RST frame bug. Should stop - * LAN workplace lockups. - * Alan Cox : Some tidyups using the new skb list facilities - * Alan Cox : sk->keepopen now seems to work - * Alan Cox : Pulls options out correctly on accepts - * Alan Cox : Fixed assorted sk->rqueue->next errors - * Alan Cox : PSH doesn't end a TCP read. Switched a bit to skb ops. - * Alan Cox : Tidied tcp_data to avoid a potential nasty. - * Alan Cox : Added some better commenting, as the tcp is hard to follow - * Alan Cox : Removed incorrect check for 20 * psh - * Michael O'Reilly : ack < copied bug fix. - * Johannes Stille : Misc tcp fixes (not all in yet). - * Alan Cox : FIN with no memory -> CRASH - * Alan Cox : Added socket option proto entries. Also added awareness of them to accept. - * Alan Cox : Added TCP options (SOL_TCP) - * Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets. - * Alan Cox : Use ip_tos/ip_ttl settings. - * Alan Cox : Handle FIN (more) properly (we hope). - * Alan Cox : RST frames sent on unsynchronised state ack error/ - * Alan Cox : Put in missing check for SYN bit. - * Alan Cox : Added tcp_select_window() aka NET2E - * window non shrink trick. - * Alan Cox : Added a couple of small NET2E timer fixes - * Charles Hedrick : TCP fixes - * Toomas Tamm : TCP window fixes - * Alan Cox : Small URG fix to rlogin ^C ack fight - * Charles Hedrick : Rewrote most of it to actually work - * Linus : Rewrote tcp_read() and URG handling - * completely - * Gerhard Koerting: Fixed some missing timer handling - * Matthew Dillon : Reworked TCP machine states as per RFC - * Gerhard Koerting: PC/TCP workarounds - * Adam Caldwell : Assorted timer/timing errors - * Matthew Dillon : Fixed another RST bug - * Alan Cox : Move to kernel side addressing changes. - * Alan Cox : Beginning work on TCP fastpathing (not yet usable) - * Arnt Gulbrandsen: Turbocharged tcp_check() routine. - * Alan Cox : TCP fast path debugging - * Alan Cox : Window clamping - * Michael Riepe : Bug in tcp_check() - * Matt Dillon : More TCP improvements and RST bug fixes - * Matt Dillon : Yet more small nasties remove from the TCP code - * (Be very nice to this man if tcp finally works 100%) 8) - * Alan Cox : BSD accept semantics. - * Alan Cox : Reset on closedown bug. - * Peter De Schrijver : ENOTCONN check missing in tcp_sendto(). - * Michael Pall : Handle select() after URG properly in all cases. - * Michael Pall : Undo the last fix in tcp_read_urg() (multi URG PUSH broke rlogin). - * Michael Pall : Fix the multi URG PUSH problem in tcp_readable(), select() after URG works now. - * Michael Pall : recv(...,MSG_OOB) never blocks in the BSD api. - * Alan Cox : Changed the semantics of sk->socket to - * fix a race and a signal problem with - * accept() and async I/O. - * Alan Cox : Relaxed the rules on tcp_sendto(). - * Yury Shevchuk : Really fixed accept() blocking problem. - * Craig I. Hagan : Allow for BSD compatible TIME_WAIT for - * clients/servers which listen in on - * fixed ports. - * Alan Cox : Cleaned the above up and shrank it to - * a sensible code size. - * Alan Cox : Self connect lockup fix. - * Alan Cox : No connect to multicast. - * Ross Biro : Close unaccepted children on master - * socket close. - * Alan Cox : Reset tracing code. - * Alan Cox : Spurious resets on shutdown. - * Alan Cox : Giant 15 minute/60 second timer error - * Alan Cox : Small whoops in selecting before an accept. - * Alan Cox : Kept the state trace facility since it's - * handy for debugging. - * Alan Cox : More reset handler fixes. - * Alan Cox : Started rewriting the code based on the RFC's - * for other useful protocol references see: - * Comer, KA9Q NOS, and for a reference on the - * difference between specifications and how BSD - * works see the 4.4lite source. - * A.N.Kuznetsov : Don't time wait on completion of tidy - * close. - * Linus Torvalds : Fin/Shutdown & copied_seq changes. - * Linus Torvalds : Fixed BSD port reuse to work first syn - * Alan Cox : Reimplemented timers as per the RFC and using multiple - * timers for sanity. - * Alan Cox : Small bug fixes, and a lot of new - * comments. - * Alan Cox : Fixed dual reader crash by locking - * the buffers (much like datagram.c) - * Alan Cox : Fixed stuck sockets in probe. A probe - * now gets fed up of retrying without - * (even a no space) answer. - * Alan Cox : Extracted closing code better - * Alan Cox : Fixed the closing state machine to - * resemble the RFC. - * Alan Cox : More 'per spec' fixes. - * Alan Cox : tcp_data() doesn't ack illegal PSH - * only frames. At least one pc tcp stack - * generates them. - * - * - * To Fix: - * Fast path the code. Two things here - fix the window calculation - * so it doesn't iterate over the queue, also spot packets with no funny - * options arriving in order and process directly. - * - * Implement RFC 1191 [Path MTU discovery] - * Look at the effect of implementing RFC 1337 suggestions and their impact. - * Rewrite output state machine to use a single queue and do low window - * situations as per the spec (RFC 1122) - * Speed up input assembly algorithm. - * RFC1323 - PAWS and window scaling. PAWS is required for IPv6 so we - * could do with it working on IPv4 - * User settable/learned rtt/max window/mtu - * Cope with MTU/device switches when retransmitting in tcp. - * Fix the window handling to use PR's new code. - * - * Change the fundamental structure to a single send queue maintained - * by TCP (removing the bogus ip stuff [thus fixing mtu drops on - * active routes too]). Cut the queue off in tcp_retransmit/ - * tcp_transmit. - * Change the receive queue to assemble as it goes. This lets us - * dispose of most of tcp_sequence, half of tcp_ack and chunks of - * tcp_data/tcp_read as well as the window shrink crud. - * Separate out duplicated code - tcp_alloc_skb, tcp_build_ack - * tcp_queue_skb seem obvious routines to extract. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or(at your option) any later version. - * - * Description of States: - * - * TCP_SYN_SENT sent a connection request, waiting for ack - * - * TCP_SYN_RECV received a connection request, sent ack, - * waiting for final ack in three-way handshake. - * - * TCP_ESTABLISHED connection established - * - * TCP_FIN_WAIT1 our side has shutdown, waiting to complete - * transmission of remaining buffered data - * - * TCP_FIN_WAIT2 all buffered data sent, waiting for remote - * to shutdown - * - * TCP_CLOSING both sides have shutdown but we still have - * data we have to finish sending - * - * TCP_TIME_WAIT timeout to catch resent junk before entering - * closed, can only be entered from FIN_WAIT2 - * or CLOSING. Required because the other end - * may not have gotten our last ACK causing it - * to retransmit the data packet (which we ignore) - * - * TCP_CLOSE_WAIT remote side has shutdown and is waiting for - * us to finish writing our data and to shutdown - * (we have to close() to move on to LAST_ACK) - * - * TCP_LAST_ACK out side has shutdown after remote has - * shutdown. There may still be data in our - * buffer that we have to finish sending - * - * TCP_CLOSE socket is finished - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "snmp.h" -#include "ip.h" -#include "protocol.h" -#include "icmp.h" -#include "tcp.h" -#include "arp.h" -#include -#include "sock.h" -#include "route.h" -#include -#include -#include -#include -#include - -/* - * The MSL timer is the 'normal' timer. - */ - -#define reset_msl_timer(x,y,z) reset_timer(x,y,z) - -#define SEQ_TICK 3 -unsigned long seq_offset; -struct tcp_mib tcp_statistics; - -static void tcp_close(struct sock *sk, int timeout); - - -/* - * The less said about this the better, but it works and will do for 1.2 - */ - -static struct wait_queue *master_select_wakeup; - -static __inline__ int min(unsigned int a, unsigned int b) -{ - if (a < b) - return(a); - return(b); -} - -#undef STATE_TRACE - -#ifdef STATE_TRACE -static char *statename[]={ - "Unused","Established","Syn Sent","Syn Recv", - "Fin Wait 1","Fin Wait 2","Time Wait", "Close", - "Close Wait","Last ACK","Listen","Closing" -}; -#endif - -static __inline__ void tcp_set_state(struct sock *sk, int state) -{ - if(sk->state==TCP_ESTABLISHED) - tcp_statistics.TcpCurrEstab--; -#ifdef STATE_TRACE - if(sk->debug) - printk("TCP sk=%p, State %s -> %s\n",sk, statename[sk->state],statename[state]); -#endif - /* This is a hack but it doesn't occur often and it's going to - be a real to fix nicely */ - - if(state==TCP_ESTABLISHED && sk->state==TCP_SYN_RECV) - { - wake_up_interruptible(&master_select_wakeup); - } - sk->state=state; - if(state==TCP_ESTABLISHED) - tcp_statistics.TcpCurrEstab++; -} - -/* - * This routine picks a TCP windows for a socket based on - * the following constraints - * - * 1. The window can never be shrunk once it is offered (RFC 793) - * 2. We limit memory per socket - * - * For now we use NET2E3's heuristic of offering half the memory - * we have handy. All is not as bad as this seems however because - * of two things. Firstly we will bin packets even within the window - * in order to get the data we are waiting for into the memory limit. - * Secondly we bin common duplicate forms at receive time - * Better heuristics welcome - */ - -int tcp_select_window(struct sock *sk) -{ - int new_window = sk->prot->rspace(sk); - - if(sk->window_clamp) - new_window=min(sk->window_clamp,new_window); - /* - * Two things are going on here. First, we don't ever offer a - * window less than min(sk->mss, MAX_WINDOW/2). This is the - * receiver side of SWS as specified in RFC1122. - * Second, we always give them at least the window they - * had before, in order to avoid retracting window. This - * is technically allowed, but RFC1122 advises against it and - * in practice it causes trouble. - * - * Fixme: This doesn't correctly handle the case where - * new_window > sk->window but not by enough to allow for the - * shift in sequence space. - */ - if (new_window < min(sk->mss, MAX_WINDOW/2) || new_window < sk->window) - return(sk->window); - return(new_window); -} - -/* - * Find someone to 'accept'. Must be called with - * sk->inuse=1 or cli() - */ - -static struct sk_buff *tcp_find_established(struct sock *s) -{ - struct sk_buff *p=skb_peek(&s->receive_queue); - if(p==NULL) - return NULL; - do - { - if(p->sk->state == TCP_ESTABLISHED || p->sk->state >= TCP_FIN_WAIT1) - return p; - p=p->next; - } - while(p!=(struct sk_buff *)&s->receive_queue); - return NULL; -} - -/* - * Remove a completed connection and return it. This is used by - * tcp_accept() to get connections from the queue. - */ - -static struct sk_buff *tcp_dequeue_established(struct sock *s) -{ - struct sk_buff *skb; - unsigned long flags; - save_flags(flags); - cli(); - skb=tcp_find_established(s); - if(skb!=NULL) - skb_unlink(skb); /* Take it off the queue */ - restore_flags(flags); - return skb; -} - -/* - * This routine closes sockets which have been at least partially - * opened, but not yet accepted. Currently it is only called by - * tcp_close, and timeout mirrors the value there. - */ - -static void tcp_close_pending (struct sock *sk) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) - { - skb->sk->dead=1; - tcp_close(skb->sk, 0); - kfree_skb(skb, FREE_READ); - } - return; -} - -/* - * Enter the time wait state. - */ - -static void tcp_time_wait(struct sock *sk) -{ - tcp_set_state(sk,TCP_TIME_WAIT); - sk->shutdown = SHUTDOWN_MASK; - if (!sk->dead) - sk->state_change(sk); - reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); -} - -/* - * A socket has timed out on its send queue and wants to do a - * little retransmitting. Currently this means TCP. - */ - -void tcp_do_retransmit(struct sock *sk, int all) -{ - struct sk_buff * skb; - struct proto *prot; - struct device *dev; - int ct=0; - - prot = sk->prot; - skb = sk->send_head; - - while (skb != NULL) - { - struct tcphdr *th; - struct iphdr *iph; - int size; - - dev = skb->dev; - IS_SKB(skb); - skb->when = jiffies; - - /* - * In general it's OK just to use the old packet. However we - * need to use the current ack and window fields. Urg and - * urg_ptr could possibly stand to be updated as well, but we - * don't keep the necessary data. That shouldn't be a problem, - * if the other end is doing the right thing. Since we're - * changing the packet, we have to issue a new IP identifier. - */ - - iph = (struct iphdr *)(skb->data + dev->hard_header_len); - th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2)); - size = skb->len - (((unsigned char *) th) - skb->data); - - /* - * Note: We ought to check for window limits here but - * currently this is done (less efficiently) elsewhere. - * We do need to check for a route change but can't handle - * that until we have the new 1.3.x buffers in. - * - */ - - iph->id = htons(ip_id_count++); - ip_send_check(iph); - - /* - * This is not the right way to handle this. We have to - * issue an up to date window and ack report with this - * retransmit to keep the odd buggy tcp that relies on - * the fact BSD does this happy. - * We don't however need to recalculate the entire - * checksum, so someone wanting a small problem to play - * with might like to implement RFC1141/RFC1624 and speed - * this up by avoiding a full checksum. - */ - - th->ack_seq = ntohl(sk->acked_seq); - th->window = ntohs(tcp_select_window(sk)); - tcp_send_check(th, sk->saddr, sk->daddr, size, sk); - - /* - * If the interface is (still) up and running, kick it. - */ - - if (dev->flags & IFF_UP) - { - /* - * If the packet is still being sent by the device/protocol - * below then don't retransmit. This is both needed, and good - - * especially with connected mode AX.25 where it stops resends - * occurring of an as yet unsent anyway frame! - * We still add up the counts as the round trip time wants - * adjusting. - */ - if (sk && !skb_device_locked(skb)) - { - /* Remove it from any existing driver queue first! */ - skb_unlink(skb); - /* Now queue it */ - ip_statistics.IpOutRequests++; - dev_queue_xmit(skb, dev, sk->priority); - } - } - - /* - * Count retransmissions - */ - - ct++; - sk->prot->retransmits ++; - - /* - * Only one retransmit requested. - */ - - if (!all) - break; - - /* - * This should cut it off before we send too many packets. - */ - - if (ct >= sk->cong_window) - break; - skb = skb->link3; - } -} - -/* - * Reset the retransmission timer - */ - -static void reset_xmit_timer(struct sock *sk, int why, unsigned long when) -{ - del_timer(&sk->retransmit_timer); - sk->ip_xmit_timeout = why; - if((int)when < 0) - { - when=3; - printk("Error: Negative timer in xmit_timer\n"); - } - sk->retransmit_timer.expires=when; - add_timer(&sk->retransmit_timer); -} - -/* - * This is the normal code called for timeouts. It does the retransmission - * and then does backoff. tcp_do_retransmit is separated out because - * tcp_ack needs to send stuff from the retransmit queue without - * initiating a backoff. - */ - - -void tcp_retransmit_time(struct sock *sk, int all) -{ - tcp_do_retransmit(sk, all); - - /* - * Increase the timeout each time we retransmit. Note that - * we do not increase the rtt estimate. rto is initialized - * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests - * that doubling rto each time is the least we can get away with. - * In KA9Q, Karn uses this for the first few times, and then - * goes to quadratic. netBSD doubles, but only goes up to *64, - * and clamps at 1 to 64 sec afterwards. Note that 120 sec is - * defined in the protocol as the maximum possible RTT. I guess - * we'll have to use something other than TCP to talk to the - * University of Mars. - * - * PAWS allows us longer timeouts and large windows, so once - * implemented ftp to mars will work nicely. We will have to fix - * the 120 second clamps though! - */ - - sk->retransmits++; - sk->backoff++; - sk->rto = min(sk->rto << 1, 120*HZ); - reset_xmit_timer(sk, TIME_WRITE, sk->rto); -} - - -/* - * A timer event has trigger a tcp retransmit timeout. The - * socket xmit queue is ready and set up to send. Because - * the ack receive code keeps the queue straight we do - * nothing clever here. - */ - -static void tcp_retransmit(struct sock *sk, int all) -{ - if (all) - { - tcp_retransmit_time(sk, all); - return; - } - - sk->ssthresh = sk->cong_window >> 1; /* remember window where we lost */ - /* sk->ssthresh in theory can be zero. I guess that's OK */ - sk->cong_count = 0; - - sk->cong_window = 1; - - /* Do the actual retransmit. */ - tcp_retransmit_time(sk, all); -} - -/* - * A write timeout has occurred. Process the after effects. - */ - -static int tcp_write_timeout(struct sock *sk) -{ - /* - * Look for a 'soft' timeout. - */ - if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) - || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) - { - /* - * Attempt to recover if arp has changed (unlikely!) or - * a route has shifted (not supported prior to 1.3). - */ - arp_destroy (sk->daddr, 0); - ip_route_check (sk->daddr); - } - /* - * Has it gone just too far ? - */ - if (sk->retransmits > TCP_RETR2) - { - sk->err = ETIMEDOUT; - sk->error_report(sk); - del_timer(&sk->retransmit_timer); - /* - * Time wait the socket - */ - if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING ) - { - tcp_set_state(sk,TCP_TIME_WAIT); - reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - } - else - { - /* - * Clean up time. - */ - tcp_set_state(sk, TCP_CLOSE); - return 0; - } - } - return 1; -} - -/* - * The TCP retransmit timer. This lacks a few small details. - * - * 1. An initial rtt timeout on the probe0 should cause what we can - * of the first write queue buffer to be split and sent. - * 2. On a 'major timeout' as defined by RFC1122 we shouldn't report - * ETIMEDOUT if we know an additional 'soft' error caused this. - * tcp_err should save a 'soft error' for us. - */ - -static void retransmit_timer(unsigned long data) -{ - struct sock *sk = (struct sock*)data; - int why = sk->ip_xmit_timeout; - - /* - * only process if socket is not in use - */ - - cli(); - if (sk->inuse || in_bh) - { - /* Try again in 1 second */ - sk->retransmit_timer.expires = HZ; - add_timer(&sk->retransmit_timer); - sti(); - return; - } - - sk->inuse = 1; - sti(); - - /* Always see if we need to send an ack. */ - - if (sk->ack_backlog && !sk->zapped) - { - sk->prot->read_wakeup (sk); - if (! sk->dead) - sk->data_ready(sk,0); - } - - /* Now we need to figure out why the socket was on the timer. */ - - switch (why) - { - /* Window probing */ - case TIME_PROBE0: - tcp_send_probe0(sk); - tcp_write_timeout(sk); - break; - /* Retransmitting */ - case TIME_WRITE: - /* It could be we got here because we needed to send an ack. - * So we need to check for that. - */ - { - struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); - cli(); - skb = sk->send_head; - if (!skb) - { - restore_flags(flags); - } - else - { - /* - * Kicked by a delayed ack. Reset timer - * correctly now - */ - if (jiffies < skb->when + sk->rto) - { - reset_xmit_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies); - restore_flags(flags); - break; - } - restore_flags(flags); - /* - * Retransmission - */ - sk->prot->retransmit (sk, 0); - tcp_write_timeout(sk); - } - break; - } - /* Sending Keepalives */ - case TIME_KEEPOPEN: - /* - * this reset_timer() call is a hack, this is not - * how KEEPOPEN is supposed to work. - */ - reset_xmit_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); - - /* Send something to keep the connection open. */ - if (sk->prot->write_wakeup) - sk->prot->write_wakeup (sk); - sk->retransmits++; - tcp_write_timeout(sk); - break; - default: - printk ("rexmit_timer: timer expired - reason unknown\n"); - break; - } - release_sock(sk); -} - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. If err < 0 then the socket should - * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. After adjustment - * header points to the first 8 bytes of the tcp header. We need - * to find the appropriate port. - */ - -void tcp_err(int err, unsigned char *header, unsigned long daddr, - unsigned long saddr, struct inet_protocol *protocol) -{ - struct tcphdr *th; - struct sock *sk; - struct iphdr *iph=(struct iphdr *)header; - - header+=4*iph->ihl; - - - th =(struct tcphdr *)header; - sk = get_sock(&tcp_prot, th->source, daddr, th->dest, saddr); - - if (sk == NULL) - return; - - if(err<0) - { - sk->err = -err; - sk->error_report(sk); - return; - } - - if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) - { - /* - * FIXME: - * For now we will just trigger a linear backoff. - * The slow start code should cause a real backoff here. - */ - if (sk->cong_window > 4) - sk->cong_window--; - return; - } - -/* sk->err = icmp_err_convert[err & 0xff].errno; -- moved as TCP should hide non fatals internally (and does) */ - - /* - * If we've already connected we will keep trying - * until we time out, or the user gives up. - */ - - if (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT) - { - if (sk->state == TCP_SYN_SENT) - { - tcp_statistics.TcpAttemptFails++; - tcp_set_state(sk,TCP_CLOSE); - sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ - } - sk->err = icmp_err_convert[err & 0xff].error; - } - return; -} - - -/* - * Walk down the receive queue counting readable data until we hit the end or we find a gap - * in the received data queue (ie a frame missing that needs sending to us). Not - * sorting using two queues as data arrives makes life so much harder. - */ - -#ifndef _HURD_ -static -#endif -int tcp_readable(struct sock *sk) -{ - unsigned long counted; - unsigned long amount; - struct sk_buff *skb; - int sum; - unsigned long flags; - - if(sk && sk->debug) - printk("tcp_readable: %p - ",sk); - - save_flags(flags); - cli(); - if (sk == NULL || (skb = skb_peek(&sk->receive_queue)) == NULL) - { - restore_flags(flags); - if(sk && sk->debug) - printk("empty\n"); - return(0); - } - - counted = sk->copied_seq; /* Where we are at the moment */ - amount = 0; - - /* - * Do until a push or until we are out of data. - */ - - do - { - if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */ - break; - sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */ - if (skb->h.th->syn) - sum++; - if (sum > 0) - { /* Add it up, move on */ - amount += sum; - if (skb->h.th->syn) - amount--; - counted += sum; - } - /* - * Don't count urg data ... but do it in the right place! - * Consider: "old_data (ptr is here) URG PUSH data" - * The old code would stop at the first push because - * it counted the urg (amount==1) and then does amount-- - * *after* the loop. This means tcp_readable() always - * returned zero if any URG PUSH was in the queue, even - * though there was normal data available. If we subtract - * the urg data right here, we even get it to work for more - * than one URG PUSH skb without normal data. - * This means that select() finally works now with urg data - * in the queue. Note that rlogin was never affected - * because it doesn't use select(); it uses two processes - * and a blocking read(). And the queue scan in tcp_read() - * was correct. Mike - */ - if (skb->h.th->urg) - amount--; /* don't count urg data */ - if (amount && skb->h.th->psh) break; - skb = skb->next; - } - while(skb != (struct sk_buff *)&sk->receive_queue); - - restore_flags(flags); - if(sk->debug) - printk("got %lu bytes.\n",amount); - return(amount); -} - -/* - * LISTEN is a special case for select.. - */ -static int tcp_listen_select(struct sock *sk, int sel_type, select_table *wait) -{ - if (sel_type == SEL_IN) { - int retval; - - sk->inuse = 1; - retval = (tcp_find_established(sk) != NULL); - release_sock(sk); - if (!retval) - select_wait(&master_select_wakeup,wait); - return retval; - } - return 0; -} - - -/* - * Wait for a TCP event. - * - * Note that we don't need to set "sk->inuse", as the upper select layers - * take care of normal races (between the test and the event) and we don't - * go look at any of the socket buffers directly. - */ -static int tcp_select(struct sock *sk, int sel_type, select_table *wait) -{ - if (sk->state == TCP_LISTEN) - return tcp_listen_select(sk, sel_type, wait); - - switch(sel_type) { - case SEL_IN: - if (sk->err) - return 1; - if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) - break; - - if (sk->shutdown & RCV_SHUTDOWN) - return 1; - - if (sk->acked_seq == sk->copied_seq) - break; - - if (sk->urg_seq != sk->copied_seq || - sk->acked_seq != sk->copied_seq+1 || - sk->urginline || !sk->urg_data) - return 1; - break; - - case SEL_OUT: - if (sk->shutdown & SEND_SHUTDOWN) - return 0; - if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) - break; - /* - * This is now right thanks to a small fix - * by Matt Dillon. - */ - - if (sk->prot->wspace(sk) < sk->mtu+128+sk->prot->max_header) - break; - return 1; - - case SEL_EX: - if (sk->err || sk->urg_data) - return 1; - break; - } - select_wait(sk->sleep, wait); - return 0; -} - -#ifndef _HURD_ -int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - int err; - switch(cmd) - { - - case TIOCINQ: -#ifdef FIXME /* FIXME: */ - case FIONREAD: -#endif - { - unsigned long amount; - - if (sk->state == TCP_LISTEN) - return(-EINVAL); - - sk->inuse = 1; - amount = tcp_readable(sk); - release_sock(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return err; - put_fs_long(amount,(unsigned long *)arg); - return(0); - } - case SIOCATMARK: - { - int answ = sk->urg_data && sk->urg_seq == sk->copied_seq; - - err = verify_area(VERIFY_WRITE,(void *) arg, - sizeof(unsigned long)); - if (err) - return err; - put_fs_long(answ,(int *) arg); - return(0); - } - case TIOCOUTQ: - { - unsigned long amount; - - if (sk->state == TCP_LISTEN) return(-EINVAL); - amount = sk->prot->wspace(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return err; - put_fs_long(amount,(unsigned long *)arg); - return(0); - } - default: - return(-EINVAL); - } -} -#endif - - - -void tcp_send_check(struct tcphdr *th, unsigned long saddr, - unsigned long daddr, int len, struct sock *sk) -{ - th->check = 0; - th->check = tcp_check(th, len, saddr, daddr); - return; -} - -/* - * This is the main buffer sending routine. We queue the buffer - * having checked it is sane seeming. - */ - -static void tcp_send_skb(struct sock *sk, struct sk_buff *skb) -{ - int size; - struct tcphdr * th = skb->h.th; - - /* - * length of packet (not counting length of pre-tcp headers) - */ - - size = skb->len - ((unsigned char *) th - skb->data); - - /* - * Sanity check it.. - */ - - if (size < sizeof(struct tcphdr) || size > skb->len) - { - printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n", - skb, skb->data, th, skb->len); - kfree_skb(skb, FREE_WRITE); - return; - } - - /* - * If we have queued a header size packet.. (these crash a few - * tcp stacks if ack is not set) - */ - - if (size == sizeof(struct tcphdr)) - { - /* If it's got a syn or fin it's notionally included in the size..*/ - if(!th->syn && !th->fin) - { - printk("tcp_send_skb: attempt to queue a bogon.\n"); - kfree_skb(skb,FREE_WRITE); - return; - } - } - - /* - * Actual processing. - */ - - tcp_statistics.TcpOutSegs++; - skb->h.seq = ntohl(th->seq) + size - 4*th->doff; - - /* - * We must queue if - * - * a) The right edge of this frame exceeds the window - * b) We are retransmitting (Nagle's rule) - * c) We have too many packets 'in flight' - */ - - if (after(skb->h.seq, sk->window_seq) || - (sk->retransmits && sk->ip_xmit_timeout == TIME_WRITE) || - sk->packets_out >= sk->cong_window) - { - /* checksum will be supplied by tcp_write_xmit. So - * we shouldn't need to set it at all. I'm being paranoid */ - th->check = 0; - if (skb->next != NULL) - { - printk("tcp_send_partial: next != NULL\n"); - skb_unlink(skb); - } - skb_queue_tail(&sk->write_queue, skb); - - /* - * If we don't fit we have to start the zero window - * probes. This is broken - we really need to do a partial - * send _first_ (This is what causes the Cisco and PC/TCP - * grief). - */ - - if (before(sk->window_seq, sk->write_queue.next->h.seq) && - sk->send_head == NULL && sk->ack_backlog == 0) - reset_xmit_timer(sk, TIME_PROBE0, sk->rto); - } - else - { - /* - * This is going straight out - */ - - th->ack_seq = ntohl(sk->acked_seq); - th->window = ntohs(tcp_select_window(sk)); - - tcp_send_check(th, sk->saddr, sk->daddr, size, sk); - - sk->sent_seq = sk->write_seq; - - /* - * This is mad. The tcp retransmit queue is put together - * by the ip layer. This causes half the problems with - * unroutable FIN's and other things. - */ - - sk->prot->queue_xmit(sk, skb->dev, skb, 0); - - /* - * Set for next retransmit based on expected ACK time. - * FIXME: We set this every time which means our - * retransmits are really about a window behind. - */ - - reset_xmit_timer(sk, TIME_WRITE, sk->rto); - } -} - -/* - * Locking problems lead us to a messy situation where we can have - * multiple partially complete buffers queued up. This is really bad - * as we don't want to be sending partial buffers. Fix this with - * a semaphore or similar to lock tcp_write per socket. - * - * These routines are pretty self descriptive. - */ - -struct sk_buff * tcp_dequeue_partial(struct sock * sk) -{ - struct sk_buff * skb; - unsigned long flags; - - save_flags(flags); - cli(); - skb = sk->partial; - if (skb) { - sk->partial = NULL; - del_timer(&sk->partial_timer); - } - restore_flags(flags); - return skb; -} - -/* - * Empty the partial queue - */ - -static void tcp_send_partial(struct sock *sk) -{ - struct sk_buff *skb; - - if (sk == NULL) - return; - while ((skb = tcp_dequeue_partial(sk)) != NULL) - tcp_send_skb(sk, skb); -} - -/* - * Queue a partial frame - */ - -void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk) -{ - struct sk_buff * tmp; - unsigned long flags; - - save_flags(flags); - cli(); - tmp = sk->partial; - if (tmp) - del_timer(&sk->partial_timer); - sk->partial = skb; - init_timer(&sk->partial_timer); - /* - * Wait up to 1 second for the buffer to fill. - */ - sk->partial_timer.expires = HZ; - sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial; - sk->partial_timer.data = (unsigned long) sk; - add_timer(&sk->partial_timer); - restore_flags(flags); - if (tmp) - tcp_send_skb(sk, tmp); -} - - -/* - * This routine sends an ack and also updates the window. - */ - -static void tcp_send_ack(unsigned long sequence, unsigned long ack, - struct sock *sk, - struct tcphdr *th, unsigned long daddr) -{ - struct sk_buff *buff; - struct tcphdr *t1; - struct device *dev = NULL; - int tmp; - - if(sk->zapped) - return; /* We have been reset, we may not send again */ - - /* - * We need to grab some memory, and put together an ack, - * and then put it into the queue to be sent. - */ - - buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC); - if (buff == NULL) - { - /* - * Force it to send an ack. We don't have to do this - * (ACK is unreliable) but it's much better use of - * bandwidth on slow links to send a spare ack than - * resend packets. - */ - - sk->ack_backlog++; - if (sk->ip_xmit_timeout != TIME_WRITE && tcp_connected(sk->state)) - { - reset_xmit_timer(sk, TIME_WRITE, HZ); - } - return; - } - - /* - * Assemble a suitable TCP frame - */ - - buff->len = sizeof(struct tcphdr); - buff->sk = sk; - buff->localroute = sk->localroute; - t1 =(struct tcphdr *) buff->data; - - /* - * Put in the IP header and routing stuff. - */ - - tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev, - IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); - if (tmp < 0) - { - buff->free = 1; - sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - return; - } - buff->len += tmp; - t1 =(struct tcphdr *)((char *)t1 +tmp); - - memcpy(t1, th, sizeof(*t1)); - - /* - * Swap the send and the receive. - */ - - t1->dest = th->source; - t1->source = th->dest; - t1->seq = ntohl(sequence); - t1->ack = 1; - sk->window = tcp_select_window(sk); - t1->window = ntohs(sk->window); - t1->res1 = 0; - t1->res2 = 0; - t1->rst = 0; - t1->urg = 0; - t1->syn = 0; - t1->psh = 0; - t1->fin = 0; - - /* - * If we have nothing queued for transmit and the transmit timer - * is on we are just doing an ACK timeout and need to switch - * to a keepalive. - */ - - if (ack == sk->acked_seq) - { - sk->ack_backlog = 0; - sk->bytes_rcv = 0; - sk->ack_timed = 0; - if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL - && sk->ip_xmit_timeout == TIME_WRITE) - { - if(sk->keepopen) { - reset_xmit_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN); - } else { - delete_timer(sk); - } - } - } - - /* - * Fill in the packet and send it - */ - - t1->ack_seq = ntohl(ack); - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk); - if (sk->debug) - printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack); - tcp_statistics.TcpOutSegs++; - sk->prot->queue_xmit(sk, dev, buff, 1); -} - - -/* - * This routine builds a generic TCP header. - */ - -extern __inline int tcp_build_header(struct tcphdr *th, struct sock *sk, int push) -{ - - memcpy(th,(void *) &(sk->dummy_th), sizeof(*th)); - th->seq = htonl(sk->write_seq); - th->psh =(push == 0) ? 1 : 0; - th->doff = sizeof(*th)/4; - th->ack = 1; - th->fin = 0; - sk->ack_backlog = 0; - sk->bytes_rcv = 0; - sk->ack_timed = 0; - th->ack_seq = htonl(sk->acked_seq); - sk->window = tcp_select_window(sk); - th->window = htons(sk->window); - - return(sizeof(*th)); -} - -/* - * This routine copies from a user buffer into a socket, - * and starts the transmit system. - */ - -static int tcp_write(struct sock *sk, unsigned char *from, - int len, int nonblock, unsigned flags) -{ - int copied = 0; - int copy; - int tmp; - struct sk_buff *skb; - struct sk_buff *send_tmp; - unsigned char *buff; - struct proto *prot; - struct device *dev = NULL; - - sk->inuse=1; - prot = sk->prot; - while(len > 0) - { - if (sk->err) - { /* Stop on an error */ - release_sock(sk); - if (copied) - return(copied); - tmp = -sk->err; - sk->err = 0; - return(tmp); - } - - /* - * First thing we do is make sure that we are established. - */ - - if (sk->shutdown & SEND_SHUTDOWN) - { - release_sock(sk); - sk->err = EPIPE; - if (copied) - return(copied); - sk->err = 0; - return(-EPIPE); - } - - /* - * Wait for a connection to finish. - */ - - while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) - { - if (sk->err) - { - release_sock(sk); - if (copied) - return(copied); - tmp = -sk->err; - sk->err = 0; - return(tmp); - } - - if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) - { - release_sock(sk); - if (copied) - return(copied); - - if (sk->err) - { - tmp = -sk->err; - sk->err = 0; - return(tmp); - } - - if (sk->keepopen) - { - send_sig(SIGPIPE, current, 0); - } - return(-EPIPE); - } - - if (nonblock || copied) - { - release_sock(sk); - if (copied) - return(copied); - return(-EAGAIN); - } - - release_sock(sk); - cli(); - - if (sk->state != TCP_ESTABLISHED && - sk->state != TCP_CLOSE_WAIT && sk->err == 0) - { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) - { - sti(); - if (copied) - return(copied); - return(-ERESTARTSYS); - } - } - sk->inuse = 1; - sti(); - } - - /* - * The following code can result in copy <= if sk->mss is ever - * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window). - * sk->mtu is constant once SYN processing is finished. I.e. we - * had better not get here until we've seen his SYN and at least one - * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.) - * But ESTABLISHED should guarantee that. sk->max_window is by definition - * non-decreasing. Note that any ioctl to set user_mss must be done - * before the exchange of SYN's. If the initial ack from the other - * end has a window of 0, max_window and thus mss will both be 0. - */ - - /* - * Now we need to check if we have a half built packet. - */ - - if ((skb = tcp_dequeue_partial(sk)) != NULL) - { - int hdrlen; - - /* IP header + TCP header */ - hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data) - + sizeof(struct tcphdr); - - /* Add more stuff to the end of skb->len */ - if (!(flags & MSG_OOB)) - { - copy = min(sk->mss - (skb->len - hdrlen), len); - /* FIXME: this is really a bug. */ - if (copy <= 0) - { - printk("TCP: **bug**: \"copy\" <= 0!!\n"); - copy = 0; - } - - memcpy_fromfs(skb->data + skb->len, from, copy); - skb->len += copy; - from += copy; - copied += copy; - len -= copy; - sk->write_seq += copy; - } - if ((skb->len - hdrlen) >= sk->mss || - (flags & MSG_OOB) || !sk->packets_out) - tcp_send_skb(sk, skb); - else - tcp_enqueue_partial(skb, sk); - continue; - } - - /* - * We also need to worry about the window. - * If window < 1/2 the maximum window we've seen from this - * host, don't use it. This is sender side - * silly window prevention, as specified in RFC1122. - * (Note that this is different than earlier versions of - * SWS prevention, e.g. RFC813.). What we actually do is - * use the whole MSS. Since the results in the right - * edge of the packet being outside the window, it will - * be queued for later rather than sent. - */ - - copy = sk->window_seq - sk->write_seq; - if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss) - copy = sk->mss; - if (copy > len) - copy = len; - - /* - * We should really check the window here also. - */ - - send_tmp = NULL; - if (copy < sk->mss && !(flags & MSG_OOB)) - { - /* - * We will release the socket in case we sleep here. - */ - release_sock(sk); - /* - * NB: following must be mtu, because mss can be increased. - * mss is always <= mtu - */ - skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header, 0, GFP_KERNEL); - sk->inuse = 1; - send_tmp = skb; - } - else - { - /* - * We will release the socket in case we sleep here. - */ - release_sock(sk); - skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL); - sk->inuse = 1; - } - - /* - * If we didn't get any memory, we need to sleep. - */ - - if (skb == NULL) - { - sk->socket->flags |= SO_NOSPACE; - if (nonblock) - { - release_sock(sk); - if (copied) - return(copied); - return(-EAGAIN); - } - - /* - * FIXME: here is another race condition. - */ - - tmp = sk->wmem_alloc; - release_sock(sk); - cli(); - /* - * Again we will try to avoid it. - */ - if (tmp <= sk->wmem_alloc && - (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT) - && sk->err == 0) - { - sk->socket->flags &= ~SO_NOSPACE; - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) - { - sti(); - if (copied) - return(copied); - return(-ERESTARTSYS); - } - } - sk->inuse = 1; - sti(); - continue; - } - - skb->len = 0; - skb->sk = sk; - skb->free = 0; - skb->localroute = sk->localroute|(flags&MSG_DONTROUTE); - - buff = skb->data; - - /* - * FIXME: we need to optimize this. - * Perhaps some hints here would be good. - */ - - tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev, - IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl); - if (tmp < 0 ) - { - prot->wfree(sk, skb->mem_addr, skb->mem_len); - release_sock(sk); - if (copied) - return(copied); - return(tmp); - } - skb->len += tmp; - skb->dev = dev; - buff += tmp; - skb->h.th =(struct tcphdr *) buff; - tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy); - if (tmp < 0) - { - prot->wfree(sk, skb->mem_addr, skb->mem_len); - release_sock(sk); - if (copied) - return(copied); - return(tmp); - } - - if (flags & MSG_OOB) - { - ((struct tcphdr *)buff)->urg = 1; - ((struct tcphdr *)buff)->urg_ptr = ntohs(copy); - } - skb->len += tmp; - memcpy_fromfs(buff+tmp, from, copy); - - from += copy; - copied += copy; - len -= copy; - skb->len += copy; - skb->free = 0; - sk->write_seq += copy; - - if (send_tmp != NULL && sk->packets_out) - { - tcp_enqueue_partial(send_tmp, sk); - continue; - } - tcp_send_skb(sk, skb); - } - sk->err = 0; - -/* - * Nagle's rule. Turn Nagle off with TCP_NODELAY for highly - * interactive fast network servers. It's meant to be on and - * it really improves the throughput though not the echo time - * on my slow slip link - Alan - */ - -/* - * Avoid possible race on send_tmp - c/o Johannes Stille - */ - - if(sk->partial && ((!sk->packets_out) - /* If not nagling we can send on the before case too.. */ - || (sk->nonagle && before(sk->write_seq , sk->window_seq)) - )) - tcp_send_partial(sk); - - release_sock(sk); - return(copied); -} - -/* - * This is just a wrapper. - */ - -static int tcp_sendto(struct sock *sk, unsigned char *from, - int len, int nonblock, unsigned flags, - struct sockaddr_in *addr, int addr_len) -{ - if (flags & ~(MSG_OOB|MSG_DONTROUTE)) - return -EINVAL; - if (sk->state == TCP_CLOSE) - return -ENOTCONN; - if (addr_len < sizeof(*addr)) - return -EINVAL; - if (addr->sin_family && addr->sin_family != AF_INET) - return -EINVAL; - if (addr->sin_port != sk->dummy_th.dest) - return -EISCONN; - if (addr->sin_addr.s_addr != sk->daddr) - return -EISCONN; - return tcp_write(sk, from, len, nonblock, flags); -} - - -/* - * Send an ack if one is backlogged at this point. Ought to merge - * this with tcp_send_ack(). - */ - -static void tcp_read_wakeup(struct sock *sk) -{ - int tmp; - struct device *dev = NULL; - struct tcphdr *t1; - struct sk_buff *buff; - - if (!sk->ack_backlog) - return; - - /* - * FIXME: we need to put code here to prevent this routine from - * being called. Being called once in a while is ok, so only check - * if this is the second time in a row. - */ - - /* - * We need to grab some memory, and put together an ack, - * and then put it into the queue to be sent. - */ - - buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); - if (buff == NULL) - { - /* Try again real soon. */ - reset_xmit_timer(sk, TIME_WRITE, HZ); - return; - } - - buff->len = sizeof(struct tcphdr); - buff->sk = sk; - buff->localroute = sk->localroute; - - /* - * Put in the IP header and routing stuff. - */ - - tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, - IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); - if (tmp < 0) - { - buff->free = 1; - sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - return; - } - - buff->len += tmp; - t1 =(struct tcphdr *)(buff->data +tmp); - - memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); - t1->seq = htonl(sk->sent_seq); - t1->ack = 1; - t1->res1 = 0; - t1->res2 = 0; - t1->rst = 0; - t1->urg = 0; - t1->syn = 0; - t1->psh = 0; - sk->ack_backlog = 0; - sk->bytes_rcv = 0; - sk->window = tcp_select_window(sk); - t1->window = ntohs(sk->window); - t1->ack_seq = ntohl(sk->acked_seq); - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); - sk->prot->queue_xmit(sk, dev, buff, 1); - tcp_statistics.TcpOutSegs++; -} - - -/* - * FIXME: - * This routine frees used buffers. - * It should consider sending an ACK to let the - * other end know we now have a bigger window. - */ - -static void cleanup_rbuf(struct sock *sk) -{ - unsigned long flags; - unsigned long left; - struct sk_buff *skb; - unsigned long rspace; - - if(sk->debug) - printk("cleaning rbuf for sk=%p\n", sk); - - save_flags(flags); - cli(); - - left = sk->prot->rspace(sk); - - /* - * We have to loop through all the buffer headers, - * and try to free up all the space we can. - */ - - while((skb=skb_peek(&sk->receive_queue)) != NULL) - { - if (!skb->used || skb->users) - break; - skb_unlink(skb); - skb->sk = sk; - kfree_skb(skb, FREE_READ); - } - - restore_flags(flags); - - /* - * FIXME: - * At this point we should send an ack if the difference - * in the window, and the amount of space is bigger than - * TCP_WINDOW_DIFF. - */ - - if(sk->debug) - printk("sk->rspace = %lu, was %lu\n", sk->prot->rspace(sk), - left); - if ((rspace=sk->prot->rspace(sk)) != left) - { - /* - * This area has caused the most trouble. The current strategy - * is to simply do nothing if the other end has room to send at - * least 3 full packets, because the ack from those will auto- - * matically update the window. If the other end doesn't think - * we have much space left, but we have room for at least 1 more - * complete packet than it thinks we do, we will send an ack - * immediately. Otherwise we will wait up to .5 seconds in case - * the user reads some more. - */ - sk->ack_backlog++; - /* - * It's unclear whether to use sk->mtu or sk->mss here. They differ only - * if the other end is offering a window smaller than the agreed on MSS - * (called sk->mtu here). In theory there's no connection between send - * and receive, and so no reason to think that they're going to send - * small packets. For the moment I'm using the hack of reducing the mss - * only on the send side, so I'm putting mtu here. - */ - - if (rspace > (sk->window - sk->bytes_rcv + sk->mtu)) - { - /* Send an ack right now. */ - tcp_read_wakeup(sk); - } - else - { - /* Force it to send an ack soon. */ - int was_active = del_timer(&sk->retransmit_timer); - if (!was_active || TCP_ACK_TIME < sk->timer.expires) - { - reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME); - } - else - add_timer(&sk->retransmit_timer); - } - } -} - - -/* - * Handle reading urgent data. BSD has very simple semantics for - * this, no blocking and very strange errors 8) - */ - -static int tcp_read_urg(struct sock * sk, int nonblock, - unsigned char *to, int len, unsigned flags) -{ - /* - * No URG data to read - */ - if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ) - return -EINVAL; /* Yes this is right ! */ - - if (sk->err) - { - int tmp = -sk->err; - sk->err = 0; - return tmp; - } - - if (sk->state == TCP_CLOSE || sk->done) - { - if (!sk->done) { - sk->done = 1; - return 0; - } - return -ENOTCONN; - } - - if (sk->shutdown & RCV_SHUTDOWN) - { - sk->done = 1; - return 0; - } - sk->inuse = 1; - if (sk->urg_data & URG_VALID) - { - char c = sk->urg_data; - if (!(flags & MSG_PEEK)) - sk->urg_data = URG_READ; - put_fs_byte(c, to); - release_sock(sk); - return 1; - } - release_sock(sk); - - /* - * Fixed the recv(..., MSG_OOB) behaviour. BSD docs and - * the available implementations agree in this case: - * this call should never block, independent of the - * blocking state of the socket. - * Mike - */ - return -EAGAIN; -} - - -/* - * This routine copies from a sock struct into the user buffer. - */ - -static int tcp_read(struct sock *sk, unsigned char *to, - int len, int nonblock, unsigned flags) -{ -#ifndef _HURD_ - struct wait_queue wait = { current, NULL }; -#endif - int copied = 0; - unsigned long peek_seq; - volatile unsigned long *seq; /* So gcc doesn't overoptimise */ - unsigned long used; - - /* - * This error should be checked. - */ - - if (sk->state == TCP_LISTEN) - return -ENOTCONN; - - /* - * Urgent data needs to be handled specially. - */ - - if (flags & MSG_OOB) - return tcp_read_urg(sk, nonblock, to, len, flags); - - /* - * Copying sequence to update. This is volatile to handle - * the multi-reader case neatly (memcpy_to/fromfs might be - * inline and thus not flush cached variables otherwise). - */ - - peek_seq = sk->copied_seq; - seq = &sk->copied_seq; - if (flags & MSG_PEEK) - seq = &peek_seq; - -#ifndef _HURD_ - add_wait_queue(sk->sleep, &wait); -#endif - sk->inuse = 1; - while (len > 0) - { - struct sk_buff * skb; - unsigned long offset; - - /* - * Are we at urgent data? Stop if we have read anything. - */ - - if (copied && sk->urg_data && sk->urg_seq == *seq) - break; - - /* - * Next get a buffer. - */ - -#ifndef _HURD_ - current->state = TASK_INTERRUPTIBLE; -#endif - - skb = skb_peek(&sk->receive_queue); - do - { - if (!skb) - break; - if (before(*seq, skb->h.th->seq)) - break; - offset = *seq - skb->h.th->seq; - if (skb->h.th->syn) - offset--; - if (offset < skb->len) - goto found_ok_skb; - if (skb->h.th->fin) - goto found_fin_ok; - if (!(flags & MSG_PEEK)) - skb->used = 1; - skb = skb->next; - } - while (skb != (struct sk_buff *)&sk->receive_queue); - - if (copied) - break; - - if (sk->err) - { - copied = -sk->err; - sk->err = 0; - break; - } - - if (sk->state == TCP_CLOSE) - { - if (!sk->done) - { - sk->done = 1; - break; - } - copied = -ENOTCONN; - break; - } - - if (sk->shutdown & RCV_SHUTDOWN) - { - sk->done = 1; - break; - } - - if (nonblock) - { - copied = -EAGAIN; - break; - } - - cleanup_rbuf(sk); - release_sock(sk); - sk->socket->flags |= SO_WAITDATA; -#ifdef _HURD_ - interruptible_sleep_on (sk->sleep); -#else - schedule(); -#endif - sk->socket->flags &= ~SO_WAITDATA; - sk->inuse = 1; - - if (current->signal & ~current->blocked) - { - copied = -ERESTARTSYS; - break; - } - continue; - - found_ok_skb: - /* - * Lock the buffer. We can be fairly relaxed as - * an interrupt will never steal a buffer we are - * using unless I've missed something serious in - * tcp_data. - */ - - skb->users++; - - /* - * Ok so how much can we use ? - */ - - used = skb->len - offset; - if (len < used) - used = len; - /* - * Do we have urgent data here? - */ - - if (sk->urg_data) - { - unsigned long urg_offset = sk->urg_seq - *seq; - if (urg_offset < used) - { - if (!urg_offset) - { - if (!sk->urginline) - { - ++*seq; - offset++; - used--; - } - } - else - used = urg_offset; - } - } - - /* - * Copy it - We _MUST_ update *seq first so that we - * don't ever double read when we have dual readers - */ - - *seq += used; - - /* - * This memcpy_tofs can sleep. If it sleeps and we - * do a second read it relies on the skb->users to avoid - * a crash when cleanup_rbuf() gets called. - */ - - memcpy_tofs(to,((unsigned char *)skb->h.th) + - skb->h.th->doff*4 + offset, used); - copied += used; - len -= used; - to += used; - - /* - * We now will not sleep again until we are finished - * with skb. Sorry if you are doing the SMP port - * but you'll just have to fix it neatly ;) - */ - - skb->users --; - - if (after(sk->copied_seq,sk->urg_seq)) - sk->urg_data = 0; - if (used + offset < skb->len) - continue; - - /* - * Process the FIN. - */ - - if (skb->h.th->fin) - goto found_fin_ok; - if (flags & MSG_PEEK) - continue; - skb->used = 1; - continue; - - found_fin_ok: - ++*seq; - if (flags & MSG_PEEK) - break; - - /* - * All is done - */ - - skb->used = 1; - sk->shutdown |= RCV_SHUTDOWN; - break; - - } -#ifndef _HURD_ - remove_wait_queue(sk->sleep, &wait); - current->state = TASK_RUNNING; -#endif - - /* Clean up data we have read: This will do ACK frames */ - cleanup_rbuf(sk); - release_sock(sk); - return copied; -} - -/* - * State processing on a close. This implements the state shift for - * sending our FIN frame. Note that we only send a FIN for some - * states. A shutdown() may have already sent the FIN, or we may be - * closed. - */ - -static int tcp_close_state(struct sock *sk, int dead) -{ - int ns=TCP_CLOSE; - int send_fin=0; - switch(sk->state) - { - case TCP_SYN_SENT: /* No SYN back, no FIN needed */ - break; - case TCP_SYN_RECV: - case TCP_ESTABLISHED: /* Closedown begin */ - ns=TCP_FIN_WAIT1; - send_fin=1; - break; - case TCP_FIN_WAIT1: /* Already closing, or FIN sent: no change */ - case TCP_FIN_WAIT2: - case TCP_CLOSING: - ns=sk->state; - break; - case TCP_CLOSE: - case TCP_LISTEN: - break; - case TCP_CLOSE_WAIT: /* They have FIN'd us. We send our FIN and - wait only for the ACK */ - ns=TCP_LAST_ACK; - send_fin=1; - } - - tcp_set_state(sk,ns); - - /* - * This is a (useful) BSD violating of the RFC. There is a - * problem with TCP as specified in that the other end could - * keep a socket open forever with no application left this end. - * We use a 3 minute timeout (about the same as BSD) then kill - * our end. If they send after that then tough - BUT: long enough - * that we won't make the old 4*rto = almost no time - whoops - * reset mistake. - */ - if(dead && ns==TCP_FIN_WAIT2) - { - int timer_active=del_timer(&sk->timer); - if(timer_active) - add_timer(&sk->timer); - else - reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT); - } - - return send_fin; -} - -/* - * Send a fin. - */ - -static void tcp_send_fin(struct sock *sk) -{ - struct proto *prot =(struct proto *)sk->prot; - struct tcphdr *th =(struct tcphdr *)&sk->dummy_th; - struct tcphdr *t1; - struct sk_buff *buff; - struct device *dev=NULL; - int tmp; - - release_sock(sk); /* in case the malloc sleeps. */ - - buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL); - sk->inuse = 1; - - if (buff == NULL) - { - /* This is a disaster if it occurs */ - printk("tcp_send_fin: Impossible malloc failure"); - return; - } - - /* - * Administrivia - */ - - buff->sk = sk; - buff->len = sizeof(*t1); - buff->localroute = sk->localroute; - t1 =(struct tcphdr *) buff->data; - - /* - * Put in the IP header and routing stuff. - */ - - tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev, - IPPROTO_TCP, sk->opt, - sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); - if (tmp < 0) - { - int t; - /* - * Finish anyway, treat this as a send that got lost. - * (Not good). - */ - - buff->free = 1; - prot->wfree(sk,buff->mem_addr, buff->mem_len); - sk->write_seq++; - t=del_timer(&sk->timer); - if(t) - add_timer(&sk->timer); - else - reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - return; - } - - /* - * We ought to check if the end of the queue is a buffer and - * if so simply add the fin to that buffer, not send it ahead. - */ - - t1 =(struct tcphdr *)((char *)t1 +tmp); - buff->len += tmp; - buff->dev = dev; - memcpy(t1, th, sizeof(*t1)); - t1->seq = ntohl(sk->write_seq); - sk->write_seq++; - buff->h.seq = sk->write_seq; - t1->ack = 1; - t1->ack_seq = ntohl(sk->acked_seq); - t1->window = ntohs(sk->window=tcp_select_window(sk)); - t1->fin = 1; - t1->rst = 0; - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); - - /* - * If there is data in the write queue, the fin must be appended to - * the write queue. - */ - - if (skb_peek(&sk->write_queue) != NULL) - { - buff->free = 0; - if (buff->next != NULL) - { - printk("tcp_send_fin: next != NULL\n"); - skb_unlink(buff); - } - skb_queue_tail(&sk->write_queue, buff); - } - else - { - sk->sent_seq = sk->write_seq; - sk->prot->queue_xmit(sk, dev, buff, 0); - reset_xmit_timer(sk, TIME_WRITE, sk->rto); - } -} - -/* - * Shutdown the sending side of a connection. Much like close except - * that we don't receive shut down or set sk->dead=1. - */ - -void tcp_shutdown(struct sock *sk, int how) -{ - /* - * We need to grab some memory, and put together a FIN, - * and then put it into the queue to be sent. - * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92. - */ - - if (!(how & SEND_SHUTDOWN)) - return; - - /* - * If we've already sent a FIN, or it's a closed state - */ - - if (sk->state == TCP_FIN_WAIT1 || - sk->state == TCP_FIN_WAIT2 || - sk->state == TCP_CLOSING || - sk->state == TCP_LAST_ACK || - sk->state == TCP_TIME_WAIT || - sk->state == TCP_CLOSE || - sk->state == TCP_LISTEN - ) - { - return; - } - sk->inuse = 1; - - /* - * flag that the sender has shutdown - */ - - sk->shutdown |= SEND_SHUTDOWN; - - /* - * Clear out any half completed packets. - */ - - if (sk->partial) - tcp_send_partial(sk); - - /* - * FIN if needed - */ - - if(tcp_close_state(sk,0)) - tcp_send_fin(sk); - - release_sock(sk); -} - - -static int -tcp_recvfrom(struct sock *sk, unsigned char *to, - int to_len, int nonblock, unsigned flags, - struct sockaddr_in *addr, int *addr_len) -{ - int result; - - /* - * Have to check these first unlike the old code. If - * we check them after we lose data on an error - * which is wrong - */ - - if(addr_len) - *addr_len = sizeof(*addr); - result=tcp_read(sk, to, to_len, nonblock, flags); - - if (result < 0) - return(result); - - if(addr) - { - addr->sin_family = AF_INET; - addr->sin_port = sk->dummy_th.dest; - addr->sin_addr.s_addr = sk->daddr; - } - return(result); -} - - -/* - * This routine will send an RST to the other tcp. - */ - -static void tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th, - struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl) -{ - struct sk_buff *buff; - struct tcphdr *t1; - int tmp; - struct device *ndev=NULL; - - /* - * Cannot reset a reset (Think about it). - */ - - if(th->rst) - return; - - /* - * We need to grab some memory, and put together an RST, - * and then put it into the queue to be sent. - */ - - buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC); - if (buff == NULL) - return; - - buff->len = sizeof(*t1); - buff->sk = NULL; - buff->dev = dev; - buff->localroute = 0; - - t1 =(struct tcphdr *) buff->data; - - /* - * Put in the IP header and routing stuff. - */ - - tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt, - sizeof(struct tcphdr),tos,ttl); - if (tmp < 0) - { - buff->free = 1; - prot->wfree(NULL, buff->mem_addr, buff->mem_len); - return; - } - - t1 =(struct tcphdr *)((char *)t1 +tmp); - buff->len += tmp; - memcpy(t1, th, sizeof(*t1)); - - /* - * Swap the send and the receive. - */ - - t1->dest = th->source; - t1->source = th->dest; - t1->rst = 1; - t1->window = 0; - - if(th->ack) - { - t1->ack = 0; - t1->seq = th->ack_seq; - t1->ack_seq = 0; - } - else - { - t1->ack = 1; - if(!th->syn) - t1->ack_seq=htonl(th->seq); - else - t1->ack_seq=htonl(th->seq+1); - t1->seq=0; - } - - t1->syn = 0; - t1->urg = 0; - t1->fin = 0; - t1->psh = 0; - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL); - prot->queue_xmit(NULL, ndev, buff, 1); - tcp_statistics.TcpOutSegs++; -} - - -/* - * Look for tcp options. Parses everything but only knows about MSS. - * This routine is always called with the packet containing the SYN. - * However it may also be called with the ack to the SYN. So you - * can't assume this is always the SYN. It's always called after - * we have set up sk->mtu to our own MTU. - * - * We need at minimum to add PAWS support here. Possibly large windows - * as Linux gets deployed on 100Mb/sec networks. - */ - -static void tcp_options(struct sock *sk, struct tcphdr *th) -{ - unsigned char *ptr; - int length=(th->doff*4)-sizeof(struct tcphdr); - int mss_seen = 0; - - ptr = (unsigned char *)(th + 1); - - while(length>0) - { - int opcode=*ptr++; - int opsize=*ptr++; - switch(opcode) - { - case TCPOPT_EOL: - return; - case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ - length--; - ptr--; /* the opsize=*ptr++ above was a mistake */ - continue; - - default: - if(opsize<=2) /* Avoid silly options looping forever */ - return; - switch(opcode) - { - case TCPOPT_MSS: - if(opsize==4 && th->syn) - { - sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr)); - mss_seen = 1; - } - break; - /* Add other options here as people feel the urge to implement stuff like large windows */ - } - ptr+=opsize-2; - length-=opsize; - } - } - if (th->syn) - { - if (! mss_seen) - sk->mtu=min(sk->mtu, 536); /* default MSS if none sent */ - } -#ifdef CONFIG_INET_PCTCP - sk->mss = min(sk->max_window >> 1, sk->mtu); -#else - sk->mss = min(sk->max_window, sk->mtu); -#endif -} - -static inline unsigned long default_mask(unsigned long dst) -{ - dst = ntohl(dst); - if (IN_CLASSA(dst)) - return htonl(IN_CLASSA_NET); - if (IN_CLASSB(dst)) - return htonl(IN_CLASSB_NET); - return htonl(IN_CLASSC_NET); -} - -/* - * Default sequence number picking algorithm. - * As close as possible to RFC 793, which - * suggests using a 250kHz clock. - * Further reading shows this assumes 2MB/s networks. - * For 10MB/s ethernet, a 1MHz clock is appropriate. - * That's funny, Linux has one built in! Use it! - */ - -extern inline unsigned long tcp_init_seq(void) -{ - struct timeval tv; - do_gettimeofday(&tv); - return tv.tv_usec+tv.tv_sec*1000000; -} - -/* - * This routine handles a connection request. - * It should make sure we haven't already responded. - * Because of the way BSD works, we have to send a syn/ack now. - * This also means it will be harder to close a socket which is - * listening. - */ - -static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, - unsigned long daddr, unsigned long saddr, - struct options *opt, struct device *dev, unsigned long seq) -{ - struct sk_buff *buff; - struct tcphdr *t1; - unsigned char *ptr; - struct sock *newsk; - struct tcphdr *th; - struct device *ndev=NULL; - int tmp; - struct rtable *rt; - - th = skb->h.th; - - /* If the socket is dead, don't accept the connection. */ - if (!sk->dead) - { - sk->data_ready(sk,0); - } - else - { - if(sk->debug) - printk("Reset on %p: Connect on dead socket.\n",sk); - tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl); - tcp_statistics.TcpAttemptFails++; - kfree_skb(skb, FREE_READ); - return; - } - - /* - * Make sure we can accept more. This will prevent a - * flurry of syns from eating up all our memory. - */ - - if (sk->ack_backlog >= sk->max_ack_backlog) - { - tcp_statistics.TcpAttemptFails++; - kfree_skb(skb, FREE_READ); - return; - } - - /* - * We need to build a new sock struct. - * It is sort of bad to have a socket without an inode attached - * to it, but the wake_up's will just wake up the listening socket, - * and if the listening socket is destroyed before this is taken - * off of the queue, this will take care of it. - */ - - newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC); - if (newsk == NULL) - { - /* just ignore the syn. It will get retransmitted. */ - tcp_statistics.TcpAttemptFails++; - kfree_skb(skb, FREE_READ); - return; - } - - memcpy(newsk, sk, sizeof(*newsk)); - skb_queue_head_init(&newsk->write_queue); - skb_queue_head_init(&newsk->receive_queue); - newsk->send_head = NULL; - newsk->send_tail = NULL; - skb_queue_head_init(&newsk->back_log); - newsk->rtt = 0; /*TCP_CONNECT_TIME<<3*/ - newsk->rto = TCP_TIMEOUT_INIT; - newsk->mdev = 0; - newsk->max_window = 0; - newsk->cong_window = 1; - newsk->cong_count = 0; - newsk->ssthresh = 0; - newsk->backoff = 0; - newsk->blog = 0; - newsk->intr = 0; - newsk->proc = 0; - newsk->done = 0; - newsk->partial = NULL; - newsk->pair = NULL; - newsk->wmem_alloc = 0; - newsk->rmem_alloc = 0; - newsk->localroute = sk->localroute; - - newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF; - - newsk->err = 0; - newsk->shutdown = 0; - newsk->ack_backlog = 0; - newsk->acked_seq = skb->h.th->seq+1; - newsk->copied_seq = skb->h.th->seq+1; - newsk->fin_seq = skb->h.th->seq; - newsk->state = TCP_SYN_RECV; - newsk->timeout = 0; - newsk->ip_xmit_timeout = 0; - newsk->write_seq = seq; - newsk->window_seq = newsk->write_seq; - newsk->rcv_ack_seq = newsk->write_seq; - newsk->urg_data = 0; - newsk->retransmits = 0; - newsk->linger=0; - newsk->destroy = 0; - init_timer(&newsk->timer); - newsk->timer.data = (unsigned long)newsk; - newsk->timer.function = &net_timer; - init_timer(&newsk->retransmit_timer); - newsk->retransmit_timer.data = (unsigned long)newsk; - newsk->retransmit_timer.function=&retransmit_timer; - newsk->dummy_th.source = skb->h.th->dest; - newsk->dummy_th.dest = skb->h.th->source; - - /* - * Swap these two, they are from our point of view. - */ - - newsk->daddr = saddr; - newsk->saddr = daddr; - - put_sock(newsk->num,newsk); - newsk->dummy_th.res1 = 0; - newsk->dummy_th.doff = 6; - newsk->dummy_th.fin = 0; - newsk->dummy_th.syn = 0; - newsk->dummy_th.rst = 0; - newsk->dummy_th.psh = 0; - newsk->dummy_th.ack = 0; - newsk->dummy_th.urg = 0; - newsk->dummy_th.res2 = 0; - newsk->acked_seq = skb->h.th->seq + 1; - newsk->copied_seq = skb->h.th->seq + 1; - newsk->socket = NULL; - - /* - * Grab the ttl and tos values and use them - */ - - newsk->ip_ttl=sk->ip_ttl; - newsk->ip_tos=skb->ip_hdr->tos; - - /* - * Use 512 or whatever user asked for - */ - - /* - * Note use of sk->user_mss, since user has no direct access to newsk - */ - - rt=ip_rt_route(saddr, NULL,NULL); - - if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) - newsk->window_clamp = rt->rt_window; - else - newsk->window_clamp = 0; - - if (sk->user_mss) - newsk->mtu = sk->user_mss; - else if(rt!=NULL && (rt->rt_flags&RTF_MSS)) - newsk->mtu = rt->rt_mss - HEADER_SIZE; - else - { -#ifdef CONFIG_INET_SNARL /* Sub Nets Are Local */ - if ((saddr ^ daddr) & default_mask(saddr)) -#else - if ((saddr ^ daddr) & dev->pa_mask) -#endif - newsk->mtu = 576 - HEADER_SIZE; - else - newsk->mtu = MAX_WINDOW; - } - - /* - * But not bigger than device MTU - */ - - newsk->mtu = min(newsk->mtu, dev->mtu - HEADER_SIZE); - - /* - * This will min with what arrived in the packet - */ - - tcp_options(newsk,skb->h.th); - - buff = newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC); - if (buff == NULL) - { - sk->err = ENOMEM; - newsk->dead = 1; - newsk->state = TCP_CLOSE; - /* And this will destroy it */ - release_sock(newsk); - kfree_skb(skb, FREE_READ); - tcp_statistics.TcpAttemptFails++; - return; - } - - buff->len = sizeof(struct tcphdr)+4; - buff->sk = newsk; - buff->localroute = newsk->localroute; - - t1 =(struct tcphdr *) buff->data; - - /* - * Put in the IP header and routing stuff. - */ - - tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &ndev, - IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl); - - /* - * Something went wrong. - */ - - if (tmp < 0) - { - sk->err = -tmp; - buff->free = 1; - kfree_skb(buff,FREE_WRITE); - newsk->dead = 1; - newsk->state = TCP_CLOSE; - release_sock(newsk); - skb->sk = sk; - kfree_skb(skb, FREE_READ); - tcp_statistics.TcpAttemptFails++; - return; - } - - buff->len += tmp; - t1 =(struct tcphdr *)((char *)t1 +tmp); - - memcpy(t1, skb->h.th, sizeof(*t1)); - buff->h.seq = newsk->write_seq; - /* - * Swap the send and the receive. - */ - t1->dest = skb->h.th->source; - t1->source = newsk->dummy_th.source; - t1->seq = ntohl(newsk->write_seq++); - t1->ack = 1; - newsk->window = tcp_select_window(newsk); - newsk->sent_seq = newsk->write_seq; - t1->window = ntohs(newsk->window); - t1->res1 = 0; - t1->res2 = 0; - t1->rst = 0; - t1->urg = 0; - t1->psh = 0; - t1->syn = 1; - t1->ack_seq = ntohl(skb->h.th->seq+1); - t1->doff = sizeof(*t1)/4+1; - ptr =(unsigned char *)(t1+1); - ptr[0] = 2; - ptr[1] = 4; - ptr[2] = ((newsk->mtu) >> 8) & 0xff; - ptr[3] =(newsk->mtu) & 0xff; - - tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk); - newsk->prot->queue_xmit(newsk, ndev, buff, 0); - reset_xmit_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT); - skb->sk = newsk; - - /* - * Charge the sock_buff to newsk. - */ - - sk->rmem_alloc -= skb->mem_len; - newsk->rmem_alloc += skb->mem_len; - - skb_queue_tail(&sk->receive_queue,skb); - sk->ack_backlog++; - release_sock(newsk); - tcp_statistics.TcpOutSegs++; -} - - -static void tcp_close(struct sock *sk, int timeout) -{ - /* - * We need to grab some memory, and put together a FIN, - * and then put it into the queue to be sent. - */ - - sk->inuse = 1; - - if(sk->state == TCP_LISTEN) - { - /* Special case */ - tcp_set_state(sk, TCP_CLOSE); - tcp_close_pending(sk); - release_sock(sk); - return; - } - - sk->keepopen = 1; - sk->shutdown = SHUTDOWN_MASK; - - if (!sk->dead) - sk->state_change(sk); - - if (timeout == 0) - { - struct sk_buff *skb; - - /* - * We need to flush the recv. buffs. We do this only on the - * descriptor close, not protocol-sourced closes, because the - * reader process may not have drained the data yet! - */ - - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) - kfree_skb(skb, FREE_READ); - /* - * Get rid off any half-completed packets. - */ - - if (sk->partial) - tcp_send_partial(sk); - } - - - /* - * Timeout is not the same thing - however the code likes - * to send both the same way (sigh). - */ - - if(timeout) - { - tcp_set_state(sk, TCP_CLOSE); /* Dead */ - } - else - { - if(tcp_close_state(sk,1)==1) - { - tcp_send_fin(sk); - } - } - release_sock(sk); -} - - -/* - * This routine takes stuff off of the write queue, - * and puts it in the xmit queue. This happens as incoming acks - * open up the remote window for us. - */ - -static void tcp_write_xmit(struct sock *sk) -{ - struct sk_buff *skb; - - /* - * The bytes will have to remain here. In time closedown will - * empty the write queue and all will be happy - */ - - if(sk->zapped) - return; - - /* - * Anything on the transmit queue that fits the window can - * be added providing we are not - * - * a) retransmitting (Nagle's rule) - * b) exceeding our congestion window. - */ - - while((skb = skb_peek(&sk->write_queue)) != NULL && - before(skb->h.seq, sk->window_seq + 1) && - (sk->retransmits == 0 || - sk->ip_xmit_timeout != TIME_WRITE || - before(skb->h.seq, sk->rcv_ack_seq + 1)) - && sk->packets_out < sk->cong_window) - { - IS_SKB(skb); - skb_unlink(skb); - - /* - * See if we really need to send the packet. - */ - - if (before(skb->h.seq, sk->rcv_ack_seq +1)) - { - /* - * This is acked data. We can discard it. This - * cannot currently occur. - */ - - sk->retransmits = 0; - kfree_skb(skb, FREE_WRITE); - if (!sk->dead) - sk->write_space(sk); - } - else - { - struct tcphdr *th; - struct iphdr *iph; - int size; -/* - * put in the ack seq and window at this point rather than earlier, - * in order to keep them monotonic. We really want to avoid taking - * back window allocations. That's legal, but RFC1122 says it's frowned on. - * Ack and window will in general have changed since this packet was put - * on the write queue. - */ - iph = (struct iphdr *)(skb->data + - skb->dev->hard_header_len); - th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2)); - size = skb->len - (((unsigned char *) th) - skb->data); - - th->ack_seq = ntohl(sk->acked_seq); - th->window = ntohs(tcp_select_window(sk)); - - tcp_send_check(th, sk->saddr, sk->daddr, size, sk); - - sk->sent_seq = skb->h.seq; - - /* - * IP manages our queue for some crazy reason - */ - - sk->prot->queue_xmit(sk, skb->dev, skb, skb->free); - - /* - * Again we slide the timer wrongly - */ - - reset_xmit_timer(sk, TIME_WRITE, sk->rto); - } - } -} - - -/* - * This routine deals with incoming acks, but not outgoing ones. - */ - -extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len) -{ - unsigned long ack; - int flag = 0; - - /* - * 1 - there was data in packet as well as ack or new data is sent or - * in shutdown state - * 2 - data from retransmit queue was acked and removed - * 4 - window shrunk or data from retransmit queue was acked and removed - */ - - if(sk->zapped) - return(1); /* Dead, cant ack any more so why bother */ - - /* - * Have we discovered a larger window - */ - - ack = ntohl(th->ack_seq); - - if (ntohs(th->window) > sk->max_window) - { - sk->max_window = ntohs(th->window); -#ifdef CONFIG_INET_PCTCP - /* Hack because we don't send partial packets to non SWS - handling hosts */ - sk->mss = min(sk->max_window>>1, sk->mtu); -#else - sk->mss = min(sk->max_window, sk->mtu); -#endif - } - - /* - * We have dropped back to keepalive timeouts. Thus we have - * no retransmits pending. - */ - - if (sk->retransmits && sk->ip_xmit_timeout == TIME_KEEPOPEN) - sk->retransmits = 0; - - /* - * If the ack is newer than sent or older than previous acks - * then we can probably ignore it. - */ - - if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq)) - { - if(sk->debug) - printk("Ack ignored %lu %lu\n",ack,sk->sent_seq); - - /* - * Keepalive processing. - */ - - if (after(ack, sk->sent_seq)) - { - return(0); - } - - /* - * Restart the keepalive timer. - */ - - if (sk->keepopen) - { - if(sk->ip_xmit_timeout==TIME_KEEPOPEN) - reset_xmit_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); - } - return(1); - } - - /* - * If there is data set flag 1 - */ - - if (len != th->doff*4) - flag |= 1; - - /* - * See if our window has been shrunk. - */ - - if (after(sk->window_seq, ack+ntohs(th->window))) - { - /* - * We may need to move packets from the send queue - * to the write queue, if the window has been shrunk on us. - * The RFC says you are not allowed to shrink your window - * like this, but if the other end does, you must be able - * to deal with it. - */ - struct sk_buff *skb; - struct sk_buff *skb2; - struct sk_buff *wskb = NULL; - - skb2 = sk->send_head; - sk->send_head = NULL; - sk->send_tail = NULL; - - /* - * This is an artifact of a flawed concept. We want one - * queue and a smarter send routine when we send all. - */ - - flag |= 4; /* Window changed */ - - sk->window_seq = ack + ntohs(th->window); - cli(); - while (skb2 != NULL) - { - skb = skb2; - skb2 = skb->link3; - skb->link3 = NULL; - if (after(skb->h.seq, sk->window_seq)) - { - if (sk->packets_out > 0) - sk->packets_out--; - /* We may need to remove this from the dev send list. */ - if (skb->next != NULL) - { - skb_unlink(skb); - } - /* Now add it to the write_queue. */ - if (wskb == NULL) - skb_queue_head(&sk->write_queue,skb); - else - skb_append(wskb,skb); - wskb = skb; - } - else - { - if (sk->send_head == NULL) - { - sk->send_head = skb; - sk->send_tail = skb; - } - else - { - sk->send_tail->link3 = skb; - sk->send_tail = skb; - } - skb->link3 = NULL; - } - } - sti(); - } - - /* - * Pipe has emptied - */ - - if (sk->send_tail == NULL || sk->send_head == NULL) - { - sk->send_head = NULL; - sk->send_tail = NULL; - sk->packets_out= 0; - } - - /* - * Update the right hand window edge of the host - */ - - sk->window_seq = ack + ntohs(th->window); - - /* - * We don't want too many packets out there. - */ - - if (sk->ip_xmit_timeout == TIME_WRITE && - sk->cong_window < 2048 && after(ack, sk->rcv_ack_seq)) - { - /* - * This is Jacobson's slow start and congestion avoidance. - * SIGCOMM '88, p. 328. Because we keep cong_window in integral - * mss's, we can't do cwnd += 1 / cwnd. Instead, maintain a - * counter and increment it once every cwnd times. It's possible - * that this should be done only if sk->retransmits == 0. I'm - * interpreting "new data is acked" as including data that has - * been retransmitted but is just now being acked. - */ - if (sk->cong_window < sk->ssthresh) - /* - * In "safe" area, increase - */ - sk->cong_window++; - else - { - /* - * In dangerous area, increase slowly. In theory this is - * sk->cong_window += 1 / sk->cong_window - */ - if (sk->cong_count >= sk->cong_window) - { - sk->cong_window++; - sk->cong_count = 0; - } - else - sk->cong_count++; - } - } - - /* - * Remember the highest ack received. - */ - - sk->rcv_ack_seq = ack; - - /* - * If this ack opens up a zero window, clear backoff. It was - * being used to time the probes, and is probably far higher than - * it needs to be for normal retransmission. - */ - - if (sk->ip_xmit_timeout == TIME_PROBE0) - { - sk->retransmits = 0; /* Our probe was answered */ - - /* - * Was it a usable window open ? - */ - - if (skb_peek(&sk->write_queue) != NULL && /* should always be non-null */ - ! before (sk->window_seq, sk->write_queue.next->h.seq)) - { - sk->backoff = 0; - - /* - * Recompute rto from rtt. this eliminates any backoff. - */ - - sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; - if (sk->rto > 120*HZ) - sk->rto = 120*HZ; - if (sk->rto < 20) /* Was 1*HZ, then 1 - turns out we must allow about - .2 of a second because of BSD delayed acks - on a 100Mb/sec link - .2 of a second is going to need huge windows (SIGH) */ - sk->rto = 20; - } - } - - /* - * See if we can take anything off of the retransmit queue. - */ - - while(sk->send_head != NULL) - { - /* Check for a bug. */ - if (sk->send_head->link3 && - after(sk->send_head->h.seq, sk->send_head->link3->h.seq)) - printk("INET: tcp.c: *** bug send_list out of order.\n"); - - /* - * If our packet is before the ack sequence we can - * discard it as it's confirmed to have arrived the other end. - */ - - if (before(sk->send_head->h.seq, ack+1)) - { - struct sk_buff *oskb; - if (sk->retransmits) - { - /* - * We were retransmitting. don't count this in RTT est - */ - flag |= 2; - - /* - * even though we've gotten an ack, we're still - * retransmitting as long as we're sending from - * the retransmit queue. Keeping retransmits non-zero - * prevents us from getting new data interspersed with - * retransmissions. - */ - - if (sk->send_head->link3) /* Any more queued retransmits? */ - sk->retransmits = 1; - else - sk->retransmits = 0; - } - /* - * Note that we only reset backoff and rto in the - * rtt recomputation code. And that doesn't happen - * if there were retransmissions in effect. So the - * first new packet after the retransmissions is - * sent with the backoff still in effect. Not until - * we get an ack from a non-retransmitted packet do - * we reset the backoff and rto. This allows us to deal - * with a situation where the network delay has increased - * suddenly. I.e. Karn's algorithm. (SIGCOMM '87, p5.) - */ - - /* - * We have one less packet out there. - */ - - if (sk->packets_out > 0) - sk->packets_out --; - /* - * Wake up the process, it can probably write more. - */ - if (!sk->dead) - sk->write_space(sk); - oskb = sk->send_head; - - if (!(flag&2)) /* Not retransmitting */ - { - long m; - - /* - * The following amusing code comes from Jacobson's - * article in SIGCOMM '88. Note that rtt and mdev - * are scaled versions of rtt and mean deviation. - * This is designed to be as fast as possible - * m stands for "measurement". - */ - - m = jiffies - oskb->when; /* RTT */ - if(m<=0) - m=1; /* IS THIS RIGHT FOR <0 ??? */ - m -= (sk->rtt >> 3); /* m is now error in rtt est */ - sk->rtt += m; /* rtt = 7/8 rtt + 1/8 new */ - if (m < 0) - m = -m; /* m is now abs(error) */ - m -= (sk->mdev >> 2); /* similar update on mdev */ - sk->mdev += m; /* mdev = 3/4 mdev + 1/4 new */ - - /* - * Now update timeout. Note that this removes any backoff. - */ - - sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; - if (sk->rto > 120*HZ) - sk->rto = 120*HZ; - if (sk->rto < 20) /* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */ - sk->rto = 20; - sk->backoff = 0; - } - flag |= (2|4); /* 2 is really more like 'don't adjust the rtt - In this case as we just set it up */ - cli(); - oskb = sk->send_head; - IS_SKB(oskb); - sk->send_head = oskb->link3; - if (sk->send_head == NULL) - { - sk->send_tail = NULL; - } - - /* - * We may need to remove this from the dev send list. - */ - - if (oskb->next) - skb_unlink(oskb); - sti(); - kfree_skb(oskb, FREE_WRITE); /* write. */ - if (!sk->dead) - sk->write_space(sk); - } - else - { - break; - } - } - - /* - * XXX someone ought to look at this too.. at the moment, if skb_peek() - * returns non-NULL, we complete ignore the timer stuff in the else - * clause. We ought to organize the code so that else clause can - * (should) be executed regardless, possibly moving the PROBE timer - * reset over. The skb_peek() thing should only move stuff to the - * write queue, NOT also manage the timer functions. - */ - - /* - * Maybe we can take some stuff off of the write queue, - * and put it onto the xmit queue. - */ - if (skb_peek(&sk->write_queue) != NULL) - { - if (after (sk->window_seq+1, sk->write_queue.next->h.seq) && - (sk->retransmits == 0 || - sk->ip_xmit_timeout != TIME_WRITE || - before(sk->write_queue.next->h.seq, sk->rcv_ack_seq + 1)) - && sk->packets_out < sk->cong_window) - { - /* - * Add more data to the send queue. - */ - flag |= 1; - tcp_write_xmit(sk); - } - else if (before(sk->window_seq, sk->write_queue.next->h.seq) && - sk->send_head == NULL && - sk->ack_backlog == 0 && - sk->state != TCP_TIME_WAIT) - { - /* - * Data to queue but no room. - */ - reset_xmit_timer(sk, TIME_PROBE0, sk->rto); - } - } - else - { - /* - * from TIME_WAIT we stay in TIME_WAIT as long as we rx packets - * from TCP_CLOSE we don't do anything - * - * from anything else, if there is write data (or fin) pending, - * we use a TIME_WRITE timeout, else if keepalive we reset to - * a KEEPALIVE timeout, else we delete the timer. - * - * We do not set flag for nominal write data, otherwise we may - * force a state where we start to write itsy bitsy tidbits - * of data. - */ - - switch(sk->state) { - case TCP_TIME_WAIT: - /* - * keep us in TIME_WAIT until we stop getting packets, - * reset the timeout. - */ - reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - break; - case TCP_CLOSE: - /* - * don't touch the timer. - */ - break; - default: - /* - * Must check send_head, write_queue, and ack_backlog - * to determine which timeout to use. - */ - if (sk->send_head || skb_peek(&sk->write_queue) != NULL || sk->ack_backlog) { - reset_xmit_timer(sk, TIME_WRITE, sk->rto); - } else if (sk->keepopen) { - reset_xmit_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); - } else { - del_timer(&sk->retransmit_timer); - sk->ip_xmit_timeout = 0; - } - break; - } - } - - /* - * We have nothing queued but space to send. Send any partial - * packets immediately (end of Nagle rule application). - */ - - if (sk->packets_out == 0 && sk->partial != NULL && - skb_peek(&sk->write_queue) == NULL && sk->send_head == NULL) - { - flag |= 1; - tcp_send_partial(sk); - } - - /* - * In the LAST_ACK case, the other end FIN'd us. We then FIN'd them, and - * we are now waiting for an acknowledge to our FIN. The other end is - * already in TIME_WAIT. - * - * Move to TCP_CLOSE on success. - */ - - if (sk->state == TCP_LAST_ACK) - { - if (!sk->dead) - sk->state_change(sk); - if(sk->debug) - printk("rcv_ack_seq: %lX==%lX, acked_seq: %lX==%lX\n", - sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq); - if (sk->rcv_ack_seq == sk->write_seq /*&& sk->acked_seq == sk->fin_seq*/) - { - flag |= 1; - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - } - } - - /* - * Incoming ACK to a FIN we sent in the case of our initiating the close. - * - * Move to FIN_WAIT2 to await a FIN from the other end. Set - * SEND_SHUTDOWN but not RCV_SHUTDOWN as data can still be coming in. - */ - - if (sk->state == TCP_FIN_WAIT1) - { - - if (!sk->dead) - sk->state_change(sk); - if (sk->rcv_ack_seq == sk->write_seq) - { - flag |= 1; - sk->shutdown |= SEND_SHUTDOWN; - tcp_set_state(sk, TCP_FIN_WAIT2); - } - } - - /* - * Incoming ACK to a FIN we sent in the case of a simultaneous close. - * - * Move to TIME_WAIT - */ - - if (sk->state == TCP_CLOSING) - { - - if (!sk->dead) - sk->state_change(sk); - if (sk->rcv_ack_seq == sk->write_seq) - { - flag |= 1; - tcp_time_wait(sk); - } - } - - /* - * Final ack of a three way shake - */ - - if(sk->state==TCP_SYN_RECV) - { - tcp_set_state(sk, TCP_ESTABLISHED); - tcp_options(sk,th); - sk->dummy_th.dest=th->source; - sk->copied_seq = sk->acked_seq; - if(!sk->dead) - sk->state_change(sk); - if(sk->max_window==0) - { - sk->max_window=32; /* Sanity check */ - sk->mss=min(sk->max_window,sk->mtu); - } - } - - /* - * I make no guarantees about the first clause in the following - * test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under - * what conditions "!flag" would be true. However I think the rest - * of the conditions would prevent that from causing any - * unnecessary retransmission. - * Clearly if the first packet has expired it should be - * retransmitted. The other alternative, "flag&2 && retransmits", is - * harder to explain: You have to look carefully at how and when the - * timer is set and with what timeout. The most recent transmission always - * sets the timer. So in general if the most recent thing has timed - * out, everything before it has as well. So we want to go ahead and - * retransmit some more. If we didn't explicitly test for this - * condition with "flag&2 && retransmits", chances are "when + rto < jiffies" - * would not be true. If you look at the pattern of timing, you can - * show that rto is increased fast enough that the next packet would - * almost never be retransmitted immediately. Then you'd end up - * waiting for a timeout to send each packet on the retransmission - * queue. With my implementation of the Karn sampling algorithm, - * the timeout would double each time. The net result is that it would - * take a hideous amount of time to recover from a single dropped packet. - * It's possible that there should also be a test for TIME_WRITE, but - * I think as long as "send_head != NULL" and "retransmit" is on, we've - * got to be in real retransmission mode. - * Note that tcp_do_retransmit is called with all==1. Setting cong_window - * back to 1 at the timeout will cause us to send 1, then 2, etc. packets. - * As long as no further losses occur, this seems reasonable. - */ - - if (((!flag) || (flag&4)) && sk->send_head != NULL && - (((flag&2) && sk->retransmits) || - (sk->send_head->when + sk->rto < jiffies))) - { - if(sk->send_head->when + sk->rto < jiffies) - tcp_retransmit(sk,0); - else - { - tcp_do_retransmit(sk, 1); - reset_xmit_timer(sk, TIME_WRITE, sk->rto); - } - } - - return(1); -} - - -/* - * Process the FIN bit. This now behaves as it is supposed to work - * and the FIN takes effect when it is validly part of sequence - * space. Not before when we get holes. - * - * If we are ESTABLISHED, a received fin moves us to CLOSE-WAIT - * (and thence onto LAST-ACK and finally, CLOSE, we never enter - * TIME-WAIT) - * - * If we are in FINWAIT-1, a received FIN indicates simultaneous - * close and we go into CLOSING (and later onto TIME-WAIT) - * - * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT. - * - */ - -static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) -{ - sk->fin_seq = th->seq + skb->len + th->syn + th->fin; - - if (!sk->dead) - { - sk->state_change(sk); - sock_wake_async(sk->socket, 1); - } - - switch(sk->state) - { - case TCP_SYN_RECV: - case TCP_SYN_SENT: - case TCP_ESTABLISHED: - /* - * move to CLOSE_WAIT, tcp_data() already handled - * sending the ack. - */ - tcp_set_state(sk,TCP_CLOSE_WAIT); - if (th->rst) - sk->shutdown = SHUTDOWN_MASK; - break; - - case TCP_CLOSE_WAIT: - case TCP_CLOSING: - /* - * received a retransmission of the FIN, do - * nothing. - */ - break; - case TCP_TIME_WAIT: - /* - * received a retransmission of the FIN, - * restart the TIME_WAIT timer. - */ - reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - return(0); - case TCP_FIN_WAIT1: - /* - * This case occurs when a simultaneous close - * happens, we must ack the received FIN and - * enter the CLOSING state. - * - * This causes a WRITE timeout, which will either - * move on to TIME_WAIT when we timeout, or resend - * the FIN properly (maybe we get rid of that annoying - * FIN lost hang). The TIME_WRITE code is already correct - * for handling this timeout. - */ - - if(sk->ip_xmit_timeout != TIME_WRITE) - reset_xmit_timer(sk, TIME_WRITE, sk->rto); - tcp_set_state(sk,TCP_CLOSING); - break; - case TCP_FIN_WAIT2: - /* - * received a FIN -- send ACK and enter TIME_WAIT - */ - reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - sk->shutdown|=SHUTDOWN_MASK; - tcp_set_state(sk,TCP_TIME_WAIT); - break; - case TCP_CLOSE: - /* - * already in CLOSE - */ - break; - default: - tcp_set_state(sk,TCP_LAST_ACK); - - /* Start the timers. */ - reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - return(0); - } - - return(0); -} - - - -/* - * This routine handles the data. If there is room in the buffer, - * it will be have already been moved into it. If there is no - * room, then we will just have to discard the packet. - */ - -extern __inline__ int tcp_data(struct sk_buff *skb, struct sock *sk, - unsigned long saddr, unsigned short len) -{ - struct sk_buff *skb1, *skb2; - struct tcphdr *th; - int dup_dumped=0; - unsigned long new_seq; - unsigned long shut_seq; - - th = skb->h.th; - skb->len = len -(th->doff*4); - - /* - * The bytes in the receive read/assembly queue has increased. Needed for the - * low memory discard algorithm - */ - - sk->bytes_rcv += skb->len; - - if (skb->len == 0 && !th->fin) - { - /* - * Don't want to keep passing ack's back and forth. - * (someone sent us dataless, boring frame) - */ - if (!th->ack) - tcp_send_ack(sk->sent_seq, sk->acked_seq,sk, th, saddr); - kfree_skb(skb, FREE_READ); - return(0); - } - - /* - * We no longer have anyone receiving data on this connection. - */ - -#ifndef TCP_DONT_RST_SHUTDOWN - - if(sk->shutdown & RCV_SHUTDOWN) - { - /* - * FIXME: BSD has some magic to avoid sending resets to - * broken 4.2 BSD keepalives. Much to my surprise a few non - * BSD stacks still have broken keepalives so we want to - * cope with it. - */ - - if(skb->len) /* We don't care if it's just an ack or - a keepalive/window probe */ - { - new_seq= th->seq + skb->len + th->syn; /* Right edge of _data_ part of frame */ - - /* Do this the way 4.4BSD treats it. Not what I'd - regard as the meaning of the spec but it's what BSD - does and clearly they know everything 8) */ - - /* - * This is valid because of two things - * - * a) The way tcp_data behaves at the bottom. - * b) A fin takes effect when read not when received. - */ - - shut_seq=sk->acked_seq+1; /* Last byte */ - - if(after(new_seq,shut_seq)) - { - if(sk->debug) - printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n", - sk, new_seq, shut_seq, sk->blog); - if(sk->dead) - { - sk->acked_seq = new_seq + th->fin; - tcp_reset(sk->saddr, sk->daddr, skb->h.th, - sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); - tcp_statistics.TcpEstabResets++; - tcp_set_state(sk,TCP_CLOSE); - sk->err = EPIPE; - sk->shutdown = SHUTDOWN_MASK; - kfree_skb(skb, FREE_READ); - return 0; - } - } - } - } - -#endif - - /* - * Now we have to walk the chain, and figure out where this one - * goes into it. This is set up so that the last packet we received - * will be the first one we look at, that way if everything comes - * in order, there will be no performance loss, and if they come - * out of order we will be able to fit things in nicely. - * - * [AC: This is wrong. We should assume in order first and then walk - * forwards from the first hole based upon real traffic patterns.] - * - */ - - if (skb_peek(&sk->receive_queue) == NULL) /* Empty queue is easy case */ - { - skb_queue_head(&sk->receive_queue,skb); - skb1= NULL; - } - else - { - for(skb1=sk->receive_queue.prev; ; skb1 = skb1->prev) - { - if(sk->debug) - { - printk("skb1=%p :", skb1); - printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq); - printk("skb->h.th->seq = %ld\n",skb->h.th->seq); - printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq, - sk->acked_seq); - } - - /* - * Optimisation: Duplicate frame or extension of previous frame from - * same sequence point (lost ack case). - * The frame contains duplicate data or replaces a previous frame - * discard the previous frame (safe as sk->inuse is set) and put - * the new one in its place. - */ - - if (th->seq==skb1->h.th->seq && skb->len>= skb1->len) - { - skb_append(skb1,skb); - skb_unlink(skb1); - kfree_skb(skb1,FREE_READ); - dup_dumped=1; - skb1=NULL; - break; - } - - /* - * Found where it fits - */ - - if (after(th->seq+1, skb1->h.th->seq)) - { - skb_append(skb1,skb); - break; - } - - /* - * See if we've hit the start. If so insert. - */ - if (skb1 == skb_peek(&sk->receive_queue)) - { - skb_queue_head(&sk->receive_queue, skb); - break; - } - } - } - - /* - * Figure out what the ack value for this frame is - */ - - th->ack_seq = th->seq + skb->len; - if (th->syn) - th->ack_seq++; - if (th->fin) - th->ack_seq++; - - if (before(sk->acked_seq, sk->copied_seq)) - { - printk("*** tcp.c:tcp_data bug acked < copied\n"); - sk->acked_seq = sk->copied_seq; - } - - /* - * Now figure out if we can ack anything. This is very messy because we really want two - * receive queues, a completed and an assembly queue. We also want only one transmit - * queue. - */ - - if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) - { - if (before(th->seq, sk->acked_seq+1)) - { - int newwindow; - - if (after(th->ack_seq, sk->acked_seq)) - { - newwindow = sk->window-(th->ack_seq - sk->acked_seq); - if (newwindow < 0) - newwindow = 0; - sk->window = newwindow; - sk->acked_seq = th->ack_seq; - } - skb->acked = 1; - - /* - * When we ack the fin, we do the FIN - * processing. - */ - - if (skb->h.th->fin) - { - tcp_fin(skb,sk,skb->h.th); - } - - for(skb2 = skb->next; - skb2 != (struct sk_buff *)&sk->receive_queue; - skb2 = skb2->next) - { - if (before(skb2->h.th->seq, sk->acked_seq+1)) - { - if (after(skb2->h.th->ack_seq, sk->acked_seq)) - { - newwindow = sk->window - - (skb2->h.th->ack_seq - sk->acked_seq); - if (newwindow < 0) - newwindow = 0; - sk->window = newwindow; - sk->acked_seq = skb2->h.th->ack_seq; - } - skb2->acked = 1; - /* - * When we ack the fin, we do - * the fin handling. - */ - if (skb2->h.th->fin) - { - tcp_fin(skb,sk,skb->h.th); - } - - /* - * Force an immediate ack. - */ - - sk->ack_backlog = sk->max_ack_backlog; - } - else - { - break; - } - } - - /* - * This also takes care of updating the window. - * This if statement needs to be simplified. - */ - if (!sk->delay_acks || - sk->ack_backlog >= sk->max_ack_backlog || - sk->bytes_rcv > sk->max_unacked || th->fin) { - /* tcp_send_ack(sk->sent_seq, sk->acked_seq,sk,th, saddr); */ - } - else - { - sk->ack_backlog++; - if(sk->debug) - printk("Ack queued.\n"); - reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME); - } - } - } - - /* - * If we've missed a packet, send an ack. - * Also start a timer to send another. - */ - - if (!skb->acked) - { - - /* - * This is important. If we don't have much room left, - * we need to throw out a few packets so we have a good - * window. Note that mtu is used, not mss, because mss is really - * for the send side. He could be sending us stuff as large as mtu. - */ - - while (sk->prot->rspace(sk) < sk->mtu) - { - skb1 = skb_peek(&sk->receive_queue); - if (skb1 == NULL) - { - printk("INET: tcp.c:tcp_data memory leak detected.\n"); - break; - } - - /* - * Don't throw out something that has been acked. - */ - - if (skb1->acked) - { - break; - } - - skb_unlink(skb1); - kfree_skb(skb1, FREE_READ); - } - tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); - sk->ack_backlog++; - reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME); - } - else - { - tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); - } - - /* - * Now tell the user we may have some data. - */ - - if (!sk->dead) - { - if(sk->debug) - printk("Data wakeup.\n"); - sk->data_ready(sk,0); - } - return(0); -} - - -/* - * This routine is only called when we have urgent data - * signalled. Its the 'slow' part of tcp_urg. It could be - * moved inline now as tcp_urg is only called from one - * place. We handle URGent data wrong. We have to - as - * BSD still doesn't use the correction from RFC961. - */ - -static void tcp_check_urg(struct sock * sk, struct tcphdr * th) -{ - unsigned long ptr = ntohs(th->urg_ptr); - - if (ptr) - ptr--; - ptr += th->seq; - - /* ignore urgent data that we've already seen and read */ - if (after(sk->copied_seq, ptr)) - return; - - /* do we already have a newer (or duplicate) urgent pointer? */ - if (sk->urg_data && !after(ptr, sk->urg_seq)) - return; - - /* tell the world about our new urgent pointer */ - if (sk->proc != 0) { - if (sk->proc > 0) { - kill_proc(sk->proc, SIGURG, 1); - } else { - kill_pg(-sk->proc, SIGURG, 1); - } - } - sk->urg_data = URG_NOTYET; - sk->urg_seq = ptr; -} - -/* - * This is the 'fast' part of urgent handling. - */ - -extern __inline__ int tcp_urg(struct sock *sk, struct tcphdr *th, - unsigned long saddr, unsigned long len) -{ - unsigned long ptr; - - /* - * Check if we get a new urgent pointer - normally not - */ - - if (th->urg) - tcp_check_urg(sk,th); - - /* - * Do we wait for any urgent data? - normally not - */ - - if (sk->urg_data != URG_NOTYET) - return 0; - - /* - * Is the urgent pointer pointing into this packet? - */ - - ptr = sk->urg_seq - th->seq + th->doff*4; - if (ptr >= len) - return 0; - - /* - * Ok, got the correct packet, update info - */ - - sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th); - if (!sk->dead) - sk->data_ready(sk,0); - return 0; -} - -/* - * This will accept the next outstanding connection. - */ - -static struct sock *tcp_accept(struct sock *sk, int flags) -{ - struct sock *newsk; - struct sk_buff *skb; - - /* - * We need to make sure that this socket is listening, - * and that it has something pending. - */ - - if (sk->state != TCP_LISTEN) - { - sk->err = EINVAL; - return(NULL); - } - - /* Avoid the race. */ - cli(); - sk->inuse = 1; - - while((skb = tcp_dequeue_established(sk)) == NULL) - { - if (flags & O_NONBLOCK) - { - sti(); - release_sock(sk); - sk->err = EAGAIN; - return(NULL); - } - - release_sock(sk); - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) - { - sti(); - sk->err = ERESTARTSYS; - return(NULL); - } - sk->inuse = 1; - } - sti(); - - /* - * Now all we need to do is return skb->sk. - */ - - newsk = skb->sk; - - kfree_skb(skb, FREE_READ); - sk->ack_backlog--; - release_sock(sk); - return(newsk); -} - - -/* - * This will initiate an outgoing connection. - */ - -static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) -{ - struct sk_buff *buff; - struct device *dev=NULL; - unsigned char *ptr; - int tmp; - int atype; - struct tcphdr *t1; - struct rtable *rt; - - if (sk->state != TCP_CLOSE) - { - return(-EISCONN); - } - - if (addr_len < 8) - return(-EINVAL); - - if (usin->sin_family && usin->sin_family != AF_INET) - return(-EAFNOSUPPORT); - - /* - * connect() to INADDR_ANY means loopback (BSD'ism). - */ - - if(usin->sin_addr.s_addr==INADDR_ANY) - usin->sin_addr.s_addr=ip_my_addr(); - - /* - * Don't want a TCP connection going to a broadcast address - */ - - if ((atype=ip_chk_addr(usin->sin_addr.s_addr)) == IS_BROADCAST || atype==IS_MULTICAST) - return -ENETUNREACH; - - sk->inuse = 1; - sk->daddr = usin->sin_addr.s_addr; - sk->write_seq = tcp_init_seq(); - sk->window_seq = sk->write_seq; - sk->rcv_ack_seq = sk->write_seq -1; - sk->err = 0; - sk->dummy_th.dest = usin->sin_port; - release_sock(sk); - - buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); - if (buff == NULL) - { - return(-ENOMEM); - } - sk->inuse = 1; - buff->len = 24; - buff->sk = sk; - buff->free = 0; - buff->localroute = sk->localroute; - - t1 = (struct tcphdr *) buff->data; - - /* - * Put in the IP header and routing stuff. - */ - - rt=ip_rt_route(sk->daddr, NULL, NULL); - - - /* - * We need to build the routing stuff from the things saved in skb. - */ - - tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, - IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl); - if (tmp < 0) - { - sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - release_sock(sk); - return(-ENETUNREACH); - } - - buff->len += tmp; - t1 = (struct tcphdr *)((char *)t1 +tmp); - - memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1)); - t1->seq = ntohl(sk->write_seq++); - sk->sent_seq = sk->write_seq; - buff->h.seq = sk->write_seq; - t1->ack = 0; - t1->window = 2; - t1->res1=0; - t1->res2=0; - t1->rst = 0; - t1->urg = 0; - t1->psh = 0; - t1->syn = 1; - t1->urg_ptr = 0; - t1->doff = 6; - /* use 512 or whatever user asked for */ - - if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) - sk->window_clamp=rt->rt_window; - else - sk->window_clamp=0; - - if (sk->user_mss) - sk->mtu = sk->user_mss; - else if(rt!=NULL && (rt->rt_flags&RTF_MTU)) - sk->mtu = rt->rt_mss; - else - { -#ifdef CONFIG_INET_SNARL - if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr)) -#else - if ((sk->saddr ^ sk->daddr) & dev->pa_mask) -#endif - sk->mtu = 576 - HEADER_SIZE; - else - sk->mtu = MAX_WINDOW; - } - /* - * but not bigger than device MTU - */ - - if(sk->mtu <32) - sk->mtu = 32; /* Sanity limit */ - - sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE); - - /* - * Put in the TCP options to say MTU. - */ - - ptr = (unsigned char *)(t1+1); - ptr[0] = 2; - ptr[1] = 4; - ptr[2] = (sk->mtu) >> 8; - ptr[3] = (sk->mtu) & 0xff; - tcp_send_check(t1, sk->saddr, sk->daddr, - sizeof(struct tcphdr) + 4, sk); - - /* - * This must go first otherwise a really quick response will get reset. - */ - - tcp_set_state(sk,TCP_SYN_SENT); - sk->rto = TCP_TIMEOUT_INIT; -#if 0 /* we already did this */ - init_timer(&sk->retransmit_timer); -#endif - sk->retransmit_timer.function=&retransmit_timer; - sk->retransmit_timer.data = (unsigned long)sk; - reset_xmit_timer(sk, TIME_WRITE, sk->rto); /* Timer for repeating the SYN until an answer */ - sk->retransmits = TCP_SYN_RETRIES; - - sk->prot->queue_xmit(sk, dev, buff, 0); - reset_xmit_timer(sk, TIME_WRITE, sk->rto); - tcp_statistics.TcpActiveOpens++; - tcp_statistics.TcpOutSegs++; - - release_sock(sk); - return(0); -} - - -/* This functions checks to see if the tcp header is actually acceptable. */ -extern __inline__ int tcp_sequence(struct sock *sk, struct tcphdr *th, short len, - struct options *opt, unsigned long saddr, struct device *dev) -{ - unsigned long next_seq; - - next_seq = len - 4*th->doff; - if (th->fin) - next_seq++; - /* if we have a zero window, we can't have any data in the packet.. */ - if (next_seq && !sk->window) - goto ignore_it; - next_seq += th->seq; - - /* - * This isn't quite right. sk->acked_seq could be more recent - * than sk->window. This is however close enough. We will accept - * slightly more packets than we should, but it should not cause - * problems unless someone is trying to forge packets. - */ - - /* have we already seen all of this packet? */ - if (!after(next_seq+1, sk->acked_seq)) - goto ignore_it; - /* or does it start beyond the window? */ - if (!before(th->seq, sk->acked_seq + sk->window + 1)) - goto ignore_it; - - /* ok, at least part of this packet would seem interesting.. */ - return 1; - -ignore_it: - if (th->rst) - return 0; - - /* - * Send a reset if we get something not ours and we are - * unsynchronized. Note: We don't do anything to our end. We - * are just killing the bogus remote connection then we will - * connect again and it will work (with luck). - */ - - if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV) - { - tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl); - return 1; - } - - /* Try to resync things. */ - tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); - return 0; -} - -/* - * When we get a reset we do this. - */ - -static int tcp_std_reset(struct sock *sk, struct sk_buff *skb) -{ - sk->zapped = 1; - sk->err = ECONNRESET; - if (sk->state == TCP_SYN_SENT) - sk->err = ECONNREFUSED; - if (sk->state == TCP_CLOSE_WAIT) - sk->err = EPIPE; -#ifdef TCP_DO_RFC1337 - /* - * Time wait assassination protection [RFC1337] - */ - if(sk->state!=TCP_TIME_WAIT) - { - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - } -#else - tcp_set_state(sk,TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; -#endif - if (!sk->dead) - sk->state_change(sk); - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); -} - -/* - * A TCP packet has arrived. - */ - -int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, - unsigned long daddr, unsigned short len, - unsigned long saddr, int redo, struct inet_protocol * protocol) -{ - struct tcphdr *th; - struct sock *sk; - int syn_ok=0; - - if (!skb) - { - printk("IMPOSSIBLE 1\n"); - return(0); - } - - if (!dev) - { - printk("IMPOSSIBLE 2\n"); - return(0); - } - - tcp_statistics.TcpInSegs++; - - if(skb->pkt_type!=PACKET_HOST) - { - kfree_skb(skb,FREE_READ); - return(0); - } - - th = skb->h.th; - - /* - * Find the socket. - */ - - sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr); - - /* - * If this socket has got a reset it's to all intents and purposes - * really dead. Count closed sockets as dead. - * - * Note: BSD appears to have a bug here. A 'closed' TCP in BSD - * simply drops data. This seems incorrect as a 'closed' TCP doesn't - * exist so should cause resets as if the port was unreachable. - */ - - if (sk!=NULL && (sk->zapped || sk->state==TCP_CLOSE)) - sk=NULL; - - if (!redo) - { - if (tcp_check(th, len, saddr, daddr )) - { - skb->sk = NULL; - kfree_skb(skb,FREE_READ); - /* - * We don't release the socket because it was - * never marked in use. - */ - return(0); - } - th->seq = ntohl(th->seq); - - /* See if we know about the socket. */ - if (sk == NULL) - { - /* - * No such TCB. If th->rst is 0 send a reset (checked in tcp_reset) - */ - tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255); - skb->sk = NULL; - /* - * Discard frame - */ - kfree_skb(skb, FREE_READ); - return(0); - } - - skb->len = len; - skb->acked = 0; - skb->used = 0; - skb->free = 0; - skb->saddr = daddr; - skb->daddr = saddr; - - /* We may need to add it to the backlog here. */ - cli(); - if (sk->inuse) - { - skb_queue_tail(&sk->back_log, skb); - sti(); - return(0); - } - sk->inuse = 1; - sti(); - } - else - { - if (sk==NULL) - { - tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255); - skb->sk = NULL; - kfree_skb(skb, FREE_READ); - return(0); - } - } - - - if (!sk->prot) - { - printk("IMPOSSIBLE 3\n"); - return(0); - } - - - /* - * Charge the memory to the socket. - */ - - if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - - skb->sk=sk; - sk->rmem_alloc += skb->mem_len; - - /* - * This basically follows the flow suggested by RFC793, with the corrections in RFC1122. We - * don't implement precedence and we process URG incorrectly (deliberately so) for BSD bug - * compatibility. We also set up variables more thoroughly [Karn notes in the - * KA9Q code the RFC793 incoming segment rules don't initialise the variables for all paths]. - */ - - if(sk->state!=TCP_ESTABLISHED) /* Skip this lot for normal flow */ - { - - /* - * Now deal with unusual cases. - */ - - if(sk->state==TCP_LISTEN) - { - if(th->ack) /* These use the socket TOS.. might want to be the received TOS */ - tcp_reset(daddr,saddr,th,sk->prot,opt,dev,sk->ip_tos, sk->ip_ttl); - - /* - * We don't care for RST, and non SYN are absorbed (old segments) - * Broadcast/multicast SYN isn't allowed. Note - bug if you change the - * netmask on a running connection it can go broadcast. Even Sun's have - * this problem so I'm ignoring it - */ - - if(th->rst || !th->syn || th->ack || ip_chk_addr(daddr)!=IS_MYADDR) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - - /* - * Guess we need to make a new socket up - */ - - tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq()); - - /* - * Now we have several options: In theory there is nothing else - * in the frame. KA9Q has an option to send data with the syn, - * BSD accepts data with the syn up to the [to be] advertised window - * and Solaris 2.1 gives you a protocol error. For now we just ignore - * it, that fits the spec precisely and avoids incompatibilities. It - * would be nice in future to drop through and process the data. - */ - - release_sock(sk); - return 0; - } - - /* retransmitted SYN? */ - if (sk->state == TCP_SYN_RECV && th->syn && th->seq+1 == sk->acked_seq) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - - /* - * SYN sent means we have to look for a suitable ack and either reset - * for bad matches or go to connected - */ - - if(sk->state==TCP_SYN_SENT) - { - /* Crossed SYN or previous junk segment */ - if(th->ack) - { - /* We got an ack, but it's not a good ack */ - if(!tcp_ack(sk,th,saddr,len)) - { - /* Reset the ack - its an ack from a - different connection [ th->rst is checked in tcp_reset()] */ - tcp_statistics.TcpAttemptFails++; - tcp_reset(daddr, saddr, th, - sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } - if(th->rst) - return tcp_std_reset(sk,skb); - if(!th->syn) - { - /* A valid ack from a different connection - start. Shouldn't happen but cover it */ - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - /* - * Ok.. it's good. Set up sequence numbers and - * move to established. - */ - syn_ok=1; /* Don't reset this connection for the syn */ - sk->acked_seq=th->seq+1; - sk->fin_seq=th->seq; - tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr); - tcp_set_state(sk, TCP_ESTABLISHED); - tcp_options(sk,th); - sk->dummy_th.dest=th->source; - sk->copied_seq = sk->acked_seq; - if(!sk->dead) - { - sk->state_change(sk); - sock_wake_async(sk->socket, 0); - } - if(sk->max_window==0) - { - sk->max_window = 32; - sk->mss = min(sk->max_window, sk->mtu); - } - } - else - { - /* See if SYN's cross. Drop if boring */ - if(th->syn && !th->rst) - { - /* Crossed SYN's are fine - but talking to - yourself is right out... */ - if(sk->saddr==saddr && sk->daddr==daddr && - sk->dummy_th.source==th->source && - sk->dummy_th.dest==th->dest) - { - tcp_statistics.TcpAttemptFails++; - return tcp_std_reset(sk,skb); - } - tcp_set_state(sk,TCP_SYN_RECV); - - /* - * FIXME: - * Must send SYN|ACK here - */ - } - /* Discard junk segment */ - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - /* - * SYN_RECV with data maybe.. drop through - */ - goto rfc_step6; - } - - /* - * BSD has a funny hack with TIME_WAIT and fast reuse of a port. There is - * a more complex suggestion for fixing these reuse issues in RFC1644 - * but not yet ready for general use. Also see RFC1379. - */ - -#define BSD_TIME_WAIT -#ifdef BSD_TIME_WAIT - if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead && - after(th->seq, sk->acked_seq) && !th->rst) - { - long seq=sk->write_seq; - if(sk->debug) - printk("Doing a BSD time wait\n"); - tcp_statistics.TcpEstabResets++; - sk->rmem_alloc -= skb->mem_len; - skb->sk = NULL; - sk->err=ECONNRESET; - tcp_set_state(sk, TCP_CLOSE); - sk->shutdown = SHUTDOWN_MASK; - release_sock(sk); - sk=get_sock(&tcp_prot, th->dest, saddr, th->source, daddr); - if (sk && sk->state==TCP_LISTEN) - { - sk->inuse=1; - skb->sk = sk; - sk->rmem_alloc += skb->mem_len; - tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000); - release_sock(sk); - return 0; - } - kfree_skb(skb, FREE_READ); - return 0; - } -#endif - } - - /* - * We are now in normal data flow (see the step list in the RFC) - * Note most of these are inline now. I'll inline the lot when - * I have time to test it hard and look at what gcc outputs - */ - - if(!tcp_sequence(sk,th,len,opt,saddr,dev)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - - if(th->rst) - return tcp_std_reset(sk,skb); - - /* - * !syn_ok is effectively the state test in RFC793. - */ - - if(th->syn && !syn_ok) - { - tcp_reset(daddr,saddr,th, &tcp_prot, opt, dev, skb->ip_hdr->tos, 255); - return tcp_std_reset(sk,skb); - } - - /* - * Process the ACK - */ - - - if(th->ack && !tcp_ack(sk,th,saddr,len)) - { - /* - * Our three way handshake failed. - */ - - if(sk->state==TCP_SYN_RECV) - { - tcp_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl); - } - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - -rfc_step6: /* I'll clean this up later */ - - /* - * Process urgent data - */ - - if(tcp_urg(sk, th, saddr, len)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - - - /* - * Process the encapsulated data - */ - - if(tcp_data(skb,sk, saddr, len)) - { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return 0; - } - - /* - * And done - */ - - release_sock(sk); - return 0; -} - -/* - * This routine sends a packet with an out of date sequence - * number. It assumes the other end will try to ack it. - */ - -static void tcp_write_wakeup(struct sock *sk) -{ - struct sk_buff *buff; - struct tcphdr *t1; - struct device *dev=NULL; - int tmp; - - if (sk->zapped) - return; /* After a valid reset we can send no more */ - - /* - * Write data can still be transmitted/retransmitted in the - * following states. If any other state is encountered, return. - * [listen/close will never occur here anyway] - */ - - if (sk->state != TCP_ESTABLISHED && - sk->state != TCP_CLOSE_WAIT && - sk->state != TCP_FIN_WAIT1 && - sk->state != TCP_LAST_ACK && - sk->state != TCP_CLOSING - ) - { - return; - } - - buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); - if (buff == NULL) - return; - - buff->len = sizeof(struct tcphdr); - buff->free = 1; - buff->sk = sk; - buff->localroute = sk->localroute; - - t1 = (struct tcphdr *) buff->data; - - /* Put in the IP header and routing stuff. */ - tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, - IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); - if (tmp < 0) - { - sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - return; - } - - buff->len += tmp; - t1 = (struct tcphdr *)((char *)t1 +tmp); - - memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); - - /* - * Use a previous sequence. - * This should cause the other end to send an ack. - */ - - t1->seq = htonl(sk->sent_seq-1); - t1->ack = 1; - t1->res1= 0; - t1->res2= 0; - t1->rst = 0; - t1->urg = 0; - t1->psh = 0; - t1->fin = 0; /* We are sending a 'previous' sequence, and 0 bytes of data - thus no FIN bit */ - t1->syn = 0; - t1->ack_seq = ntohl(sk->acked_seq); - t1->window = ntohs(tcp_select_window(sk)); - t1->doff = sizeof(*t1)/4; - tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); - /* - * Send it and free it. - * This will prevent the timer from automatically being restarted. - */ - sk->prot->queue_xmit(sk, dev, buff, 1); - tcp_statistics.TcpOutSegs++; -} - -/* - * A window probe timeout has occurred. - */ - -void tcp_send_probe0(struct sock *sk) -{ - if (sk->zapped) - return; /* After a valid reset we can send no more */ - - tcp_write_wakeup(sk); - - sk->backoff++; - sk->rto = min(sk->rto << 1, 120*HZ); - reset_xmit_timer (sk, TIME_PROBE0, sk->rto); - sk->retransmits++; - sk->prot->retransmits ++; -} - -/* - * Socket option code for TCP. - */ - -int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) -{ - int val,err; - - if(level!=SOL_TCP) - return ip_setsockopt(sk,level,optname,optval,optlen); - - if (optval == NULL) - return(-EINVAL); - - err=verify_area(VERIFY_READ, optval, sizeof(int)); - if(err) - return err; - - val = get_fs_long((unsigned long *)optval); - - switch(optname) - { - case TCP_MAXSEG: -/* - * values greater than interface MTU won't take effect. however at - * the point when this call is done we typically don't yet know - * which interface is going to be used - */ - if(val<1||val>MAX_WINDOW) - return -EINVAL; - sk->user_mss=val; - return 0; - case TCP_NODELAY: - sk->nonagle=(val==0)?0:1; - return 0; - default: - return(-ENOPROTOOPT); - } -} - -int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) -{ - int val,err; - - if(level!=SOL_TCP) - return ip_getsockopt(sk,level,optname,optval,optlen); - - switch(optname) - { - case TCP_MAXSEG: - val=sk->user_mss; - break; - case TCP_NODELAY: - val=sk->nonagle; - break; - default: - return(-ENOPROTOOPT); - } - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; - put_fs_long(sizeof(int),(unsigned long *) optlen); - - err=verify_area(VERIFY_WRITE, optval, sizeof(int)); - if(err) - return err; - put_fs_long(val,(unsigned long *)optval); - - return(0); -} - - -struct proto tcp_prot = { - sock_wmalloc, - sock_rmalloc, - sock_wfree, - sock_rfree, - sock_rspace, - sock_wspace, - tcp_close, - tcp_read, - tcp_write, - tcp_sendto, - tcp_recvfrom, - ip_build_header, - tcp_connect, - tcp_accept, - ip_queue_xmit, - tcp_retransmit, - tcp_write_wakeup, - tcp_read_wakeup, - tcp_rcv, - tcp_select, -#ifdef _HURD_ - NULL, -#else - tcp_ioctl, -#endif - NULL, - tcp_shutdown, - tcp_setsockopt, - tcp_getsockopt, - 128, - 0, - {NULL,}, - "TCP", - 0, 0 -}; - -/* - * This routine computes a TCP checksum. - */ - -unsigned short tcp_check(struct tcphdr *th, int len, - unsigned long saddr, unsigned long daddr) -{ - unsigned long sum; - - if (saddr == 0) saddr = ip_my_addr(); - -/* - * stupid, gcc complains when I use just one __asm__ block, - * something about too many reloads, but this is just two - * instructions longer than what I want - */ - __asm__(" - addl %%ecx, %%ebx - adcl %%edx, %%ebx - adcl $0, %%ebx - " - : "=b"(sum) - : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256) - : "bx", "cx", "dx" ); - __asm__(" - movl %%ecx, %%edx - cld - cmpl $32, %%ecx - jb 2f - shrl $5, %%ecx - clc -1: lodsl - adcl %%eax, %%ebx - lodsl - adcl %%eax, %%ebx - lodsl - adcl %%eax, %%ebx - lodsl - adcl %%eax, %%ebx - lodsl - adcl %%eax, %%ebx - lodsl - adcl %%eax, %%ebx - lodsl - adcl %%eax, %%ebx - lodsl - adcl %%eax, %%ebx - loop 1b - adcl $0, %%ebx - movl %%edx, %%ecx -2: andl $28, %%ecx - je 4f - shrl $2, %%ecx - clc -3: lodsl - adcl %%eax, %%ebx - loop 3b - adcl $0, %%ebx -4: movl $0, %%eax - testw $2, %%dx - je 5f - lodsw - addl %%eax, %%ebx - adcl $0, %%ebx - movw $0, %%ax -5: test $1, %%edx - je 6f - lodsb - addl %%eax, %%ebx - adcl $0, %%ebx -6: movl %%ebx, %%eax - shrl $16, %%eax - addw %%ax, %%bx - adcw $0, %%bx - " - : "=b"(sum) - : "0"(sum), "c"(len), "S"(th) - : "ax", "bx", "cx", "dx", "si" ); - - /* We only want the bottom 16 bits, but we never cleared the top 16. */ - - return((~sum) & 0xffff); -} - diff --git a/pfinet/linux-inet/tcp.h b/pfinet/linux-inet/tcp.h deleted file mode 100644 index 016fa6dd..00000000 --- a/pfinet/linux-inet/tcp.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the TCP module. - * - * Version: @(#)tcp.h 1.0.5 05/23/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _TCP_H -#define _TCP_H - -#include - -#define MAX_SYN_SIZE 44 + MAX_HEADER -#define MAX_FIN_SIZE 40 + MAX_HEADER -#define MAX_ACK_SIZE 40 + MAX_HEADER -#define MAX_RESET_SIZE 40 + MAX_HEADER -#define MAX_WINDOW 16384 -#define MIN_WINDOW 2048 -#define MAX_ACK_BACKLOG 2 -#define MIN_WRITE_SPACE 2048 -#define TCP_WINDOW_DIFF 2048 - -/* urg_data states */ -#define URG_VALID 0x0100 -#define URG_NOTYET 0x0200 -#define URG_READ 0x0400 - -#define TCP_RETR1 7 /* - * This is how many retries it does before it - * tries to figure out if the gateway is - * down. - */ - -#define TCP_RETR2 15 /* - * This should take at least - * 90 minutes to time out. - */ - -#define TCP_TIMEOUT_LEN (15*60*HZ) /* should be about 15 mins */ -#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to successfully - * close the socket, about 60 seconds */ -#define TCP_FIN_TIMEOUT (3*60*HZ) /* BSD style FIN_WAIT2 deadlock breaker */ -#define TCP_ACK_TIME (3*HZ) /* time to delay before sending an ACK */ -#define TCP_DONE_TIME 250 /* maximum time to wait before actually - * destroying a socket */ -#define TCP_WRITE_TIME 3000 /* initial time to wait for an ACK, - * after last transmit */ -#define TCP_TIMEOUT_INIT (3*HZ) /* RFC 1122 initial timeout value */ -#define TCP_SYN_RETRIES 5 /* number of times to retry opening a - * connection */ -#define TCP_PROBEWAIT_LEN 100 /* time to wait between probes when - * I've got something to write and - * there is no window */ - -#define TCP_NO_CHECK 0 /* turn to one if you want the default - * to be no checksum */ - - -/* - * TCP option - */ - -#define TCPOPT_NOP 1 /* Padding */ -#define TCPOPT_EOL 0 /* End of options */ -#define TCPOPT_MSS 2 /* Segment size negotiating */ -/* - * We don't use these yet, but they are for PAWS and big windows - */ -#define TCPOPT_WINDOW 3 /* Window scaling */ -#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ - - -/* - * The next routines deal with comparing 32 bit unsigned ints - * and worry about wraparound (automatic with unsigned arithmetic). - */ - -extern __inline int before(unsigned long seq1, unsigned long seq2) -{ - return (long)(seq1-seq2) < 0; -} - -extern __inline int after(unsigned long seq1, unsigned long seq2) -{ - return (long)(seq1-seq2) > 0; -} - - -/* is s2<=s1<=s3 ? */ -extern __inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3) -{ - return (after(seq1+1, seq2) && before(seq1, seq3+1)); -} - - -/* - * List all states of a TCP socket that can be viewed as a "connected" - * state. This now includes TCP_SYN_RECV, although I am not yet fully - * convinced that this is the solution for the 'getpeername(2)' - * problem. Thanks to Stephen A. Wood -FvK - */ -extern __inline const int -tcp_connected(const int state) -{ - return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT || - state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 || - state == TCP_SYN_RECV); -} - - -extern struct proto tcp_prot; - - -extern void tcp_err(int err, unsigned char *header, unsigned long daddr, - unsigned long saddr, struct inet_protocol *protocol); -extern void tcp_shutdown (struct sock *sk, int how); -extern int tcp_rcv(struct sk_buff *skb, struct device *dev, - struct options *opt, unsigned long daddr, - unsigned short len, unsigned long saddr, int redo, - struct inet_protocol *protocol); - -extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); - -extern int tcp_select_window(struct sock *sk); -extern void tcp_send_check(struct tcphdr *th, unsigned long saddr, - unsigned long daddr, int len, struct sock *sk); -extern void tcp_send_probe0(struct sock *sk); -extern void tcp_enqueue_partial(struct sk_buff *, struct sock *); -extern struct sk_buff * tcp_dequeue_partial(struct sock *); - - -#endif /* _TCP_H */ diff --git a/pfinet/linux-inet/timer.c b/pfinet/linux-inet/timer.c deleted file mode 100644 index 4fbbc74b..00000000 --- a/pfinet/linux-inet/timer.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * TIMER - implementation of software timers for IP. - * - * Version: @(#)timer.c 1.0.7 05/25/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Corey Minyard - * Fred Baumgarten, - * Florian La Roche, - * - * Fixes: - * Alan Cox : To avoid destroying a wait queue as we use it - * we defer destruction until the destroy timer goes - * off. - * Alan Cox : Destroy socket doesn't write a status value to the - * socket buffer _AFTER_ freeing it! Also sock ensures - * the socket will get removed BEFORE this is called - * otherwise if the timer TIME_DESTROY occurs inside - * of inet_bh() with this socket being handled it goes - * BOOM! Have to stop timer going off if net_bh is - * active or the destroy causes crashes. - * Alan Cox : Cleaned up unused code. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include "tcp.h" -#include -#include "sock.h" -#include "arp.h" - -void delete_timer (struct sock *t) -{ - unsigned long flags; - - save_flags (flags); - cli(); - - t->timeout = 0; - del_timer (&t->timer); - - restore_flags (flags); -} - -void reset_timer (struct sock *t, int timeout, unsigned long len) -{ - delete_timer (t); - t->timeout = timeout; -#if 1 - /* FIXME: ??? */ - if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */ - len = 3; /* happen (negative values ?) - don't ask me why ! -FB */ -#endif - t->timer.expires = len; - add_timer (&t->timer); -} - - -/* - * Now we will only be called whenever we need to do - * something, but we must be sure to process all of the - * sockets that need it. - */ - -void net_timer (unsigned long data) -{ - struct sock *sk = (struct sock*)data; - int why = sk->timeout; - - /* - * only process if socket is not in use - */ - - cli(); - if (sk->inuse || in_bh) - { - sk->timer.expires = 10; - add_timer(&sk->timer); - sti(); - return; - } - - sk->inuse = 1; - sti(); - - /* Always see if we need to send an ack. */ - - if (sk->ack_backlog && !sk->zapped) - { - sk->prot->read_wakeup (sk); - if (! sk->dead) - sk->data_ready(sk,0); - } - - /* Now we need to figure out why the socket was on the timer. */ - - switch (why) - { - case TIME_DONE: - if (! sk->dead || sk->state != TCP_CLOSE) - { - printk ("non dead socket in time_done\n"); - release_sock (sk); - break; - } - destroy_sock (sk); - break; - - case TIME_DESTROY: - /* - * We've waited for a while for all the memory associated with - * the socket to be freed. - */ - if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0) - { - sk->wmem_alloc++; /* So it DOESN'T go away */ - destroy_sock (sk); - sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */ - sk->inuse = 0; /* This will be ok, the destroy won't totally work */ - } - if(sk->wmem_alloc==0 && sk->rmem_alloc==0) - destroy_sock(sk); /* Socket gone, DON'T update sk->inuse! */ - break; - case TIME_CLOSE: - /* We've waited long enough, close the socket. */ - sk->state = TCP_CLOSE; - delete_timer (sk); - /* Kill the ARP entry in case the hardware has changed. */ - arp_destroy (sk->daddr, 0); - if (!sk->dead) - sk->state_change(sk); - sk->shutdown = SHUTDOWN_MASK; - reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME); - release_sock (sk); - break; -#if 0 - case TIME_PROBE0: - tcp_send_probe0(sk); - release_sock (sk); - break; - case TIME_WRITE: /* try to retransmit. */ - /* It could be we got here because we needed to send an ack. - * So we need to check for that. - */ - { - struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); - cli(); - skb = sk->send_head; - if (!skb) - { - restore_flags(flags); - } - else - { - if (jiffies < skb->when + sk->rto) - { - reset_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies); - restore_flags(flags); - release_sock (sk); - break; - } - restore_flags(flags); - /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq, - sk->retransmits, sk->packets_out, sk->cong_window); */ - sk->prot->retransmit (sk, 0); - if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) - || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) - { - arp_destroy (sk->daddr, 0); - ip_route_check (sk->daddr); - } - if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) - { - sk->err = ETIMEDOUT; - if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING) - { - sk->state = TCP_TIME_WAIT; - reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - } - else - { - sk->prot->close (sk, 1); - break; - } - } - } - release_sock (sk); - break; - } - case TIME_KEEPOPEN: - /* - * this reset_timer() call is a hack, this is not - * how KEEPOPEN is supposed to work. - */ - reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); - - /* Send something to keep the connection open. */ - if (sk->prot->write_wakeup) - sk->prot->write_wakeup (sk); - sk->retransmits++; - if (sk->shutdown == SHUTDOWN_MASK) - { - sk->prot->close (sk, 1); - sk->state = TCP_CLOSE; - } - if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) - || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) - { - arp_destroy (sk->daddr, 0); - ip_route_check (sk->daddr); - release_sock (sk); - break; - } - if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) - { - arp_destroy (sk->daddr, 0); - sk->err = ETIMEDOUT; - if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) - { - sk->state = TCP_TIME_WAIT; - if (!sk->dead) - sk->state_change(sk); - release_sock (sk); - } - else - { - sk->prot->close (sk, 1); - } - break; - } - release_sock (sk); - break; -#endif - default: - printk ("net_timer: timer expired - reason %d is unknown\n", why); - release_sock (sk); - break; - } -} - diff --git a/pfinet/linux-inet/udp.c b/pfinet/linux-inet/udp.c deleted file mode 100644 index 420f24b3..00000000 --- a/pfinet/linux-inet/udp.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The User Datagram Protocol (UDP). - * - * Version: @(#)udp.c 1.0.13 06/02/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : verify_area() calls - * Alan Cox : stopped close while in use off icmp - * messages. Not a fix but a botch that - * for udp at least is 'valid'. - * Alan Cox : Fixed icmp handling properly - * Alan Cox : Correct error for oversized datagrams - * Alan Cox : Tidied select() semantics. - * Alan Cox : udp_err() fixed properly, also now - * select and read wake correctly on errors - * Alan Cox : udp_send verify_area moved to avoid mem leak - * Alan Cox : UDP can count its memory - * Alan Cox : send to an unknown connection causes - * an ECONNREFUSED off the icmp, but - * does NOT close. - * Alan Cox : Switched to new sk_buff handlers. No more backlog! - * Alan Cox : Using generic datagram code. Even smaller and the PEEK - * bug no longer crashes it. - * Fred Van Kempen : Net2e support for sk->broadcast. - * Alan Cox : Uses skb_free_datagram - * Alan Cox : Added get/set sockopt support. - * Alan Cox : Broadcasting without option set returns EACCES. - * Alan Cox : No wakeup calls. Instead we now use the callbacks. - * Alan Cox : Use ip_tos and ip_ttl - * Alan Cox : SNMP Mibs - * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. - * Matt Dillon : UDP length checks. - * Alan Cox : Smarter af_inet used properly. - * Alan Cox : Use new kernel side addressing. - * Alan Cox : Incorrect return on truncated datagram receive. - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "snmp.h" -#include "ip.h" -#include "protocol.h" -#include "tcp.h" -#include -#include "sock.h" -#include "udp.h" -#include "icmp.h" -#include "route.h" - -/* - * SNMP MIB for the UDP layer - */ - -struct udp_mib udp_statistics; - - -static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len); - -#define min(a,b) ((a)<(b)?(a):(b)) - - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. If err < 0 then the socket should - * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. - * Header points to the ip header of the error packet. We move - * on past this. Then (as it used to claim before adjustment) - * header points to the first 8 bytes of the udp header. We need - * to find the appropriate port. - */ - -void udp_err(int err, unsigned char *header, unsigned long daddr, - unsigned long saddr, struct inet_protocol *protocol) -{ - struct udphdr *th; - struct sock *sk; - struct iphdr *ip=(struct iphdr *)header; - - header += 4*ip->ihl; - - /* - * Find the 8 bytes of post IP header ICMP included for us - */ - - th = (struct udphdr *)header; - - sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr); - - if (sk == NULL) - return; /* No socket for error */ - - if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) - { /* Slow down! */ - if (sk->cong_window > 1) - sk->cong_window = sk->cong_window/2; - return; - } - - /* - * Various people wanted BSD UDP semantics. Well they've come - * back out because they slow down response to stuff like dead - * or unreachable name servers and they screw term users something - * chronic. Oh and it violates RFC1122. So basically fix your - * client code people. - */ - -#ifdef CONFIG_I_AM_A_BROKEN_BSD_WEENIE - /* - * It's only fatal if we have connected to them. I'm not happy - * with this code. Some BSD comparisons need doing. - */ - - if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) - { - sk->err = icmp_err_convert[err & 0xff].errno; - sk->error_report(sk); - } -#else - if (icmp_err_convert[err & 0xff].fatal) - { - sk->err = icmp_err_convert[err & 0xff].error; - sk->error_report(sk); - } -#endif -} - - - -/* - * Generate UDP checksums. These may be disabled, eg for fast NFS over ethernet - * We default them enabled.. if you turn them off you either know what you are - * doing or get burned... - */ - -static void udp_send_check(struct udphdr *uh, unsigned long saddr, - unsigned long daddr, int len, struct sock *sk) -{ - uh->check = 0; - if (sk && sk->no_check) - return; - uh->check = udp_check(uh, len, saddr, daddr); - - /* - * FFFF and 0 are the same, pick the right one as 0 in the - * actual field means no checksum. - */ - - if (uh->check == 0) - uh->check = 0xffff; -} - - -static int udp_send(struct sock *sk, struct sockaddr_in *sin, - unsigned char *from, int len, int rt) -{ - struct sk_buff *skb; - struct device *dev; - struct udphdr *uh; - unsigned char *buff; - unsigned long saddr; - int size, tmp; - int ttl; - - /* - * Allocate an sk_buff copy of the packet. - */ - - size = sk->prot->max_header + len; - skb = sock_alloc_send_skb(sk, size, 0, &tmp); - - - if (skb == NULL) - return tmp; - - skb->sk = NULL; /* to avoid changing sk->saddr */ - skb->free = 1; - skb->localroute = sk->localroute|(rt&MSG_DONTROUTE); - - /* - * Now build the IP and MAC header. - */ - - buff = skb->data; - saddr = sk->saddr; - dev = NULL; - ttl = sk->ip_ttl; -#ifdef CONFIG_IP_MULTICAST - if (MULTICAST(sin->sin_addr.s_addr)) - ttl = sk->ip_mc_ttl; -#endif - tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr, - &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl); - - skb->sk=sk; /* So memory is freed correctly */ - - /* - * Unable to put a header on the packet. - */ - - if (tmp < 0 ) - { - sk->prot->wfree(sk, skb->mem_addr, skb->mem_len); - return(tmp); - } - - buff += tmp; - saddr = skb->saddr; /*dev->pa_addr;*/ - skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */ - skb->dev = dev; - - /* - * Fill in the UDP header. - */ - - uh = (struct udphdr *) buff; - uh->len = htons(len + sizeof(struct udphdr)); - uh->source = sk->dummy_th.source; - uh->dest = sin->sin_port; - buff = (unsigned char *) (uh + 1); - - /* - * Copy the user data. - */ - - memcpy_fromfs(buff, from, len); - - /* - * Set up the UDP checksum. - */ - - udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk); - - /* - * Send the datagram to the interface. - */ - - udp_statistics.UdpOutDatagrams++; - - sk->prot->queue_xmit(sk, dev, skb, 1); - return(len); -} - - -static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock, - unsigned flags, struct sockaddr_in *usin, int addr_len) -{ - struct sockaddr_in sin; - int tmp; - - /* - * Check the flags. We support no flags for UDP sending - */ - if (flags&~MSG_DONTROUTE) - return(-EINVAL); - /* - * Get and verify the address. - */ - - if (usin) - { - if (addr_len < sizeof(sin)) - return(-EINVAL); - memcpy(&sin,usin,sizeof(sin)); - if (sin.sin_family && sin.sin_family != AF_INET) - return(-EINVAL); - if (sin.sin_port == 0) - return(-EINVAL); - } - else - { - if (sk->state != TCP_ESTABLISHED) - return(-EINVAL); - sin.sin_family = AF_INET; - sin.sin_port = sk->dummy_th.dest; - sin.sin_addr.s_addr = sk->daddr; - } - - /* - * BSD socket semantics. You must set SO_BROADCAST to permit - * broadcasting of data. - */ - - if(sin.sin_addr.s_addr==INADDR_ANY) - sin.sin_addr.s_addr=ip_my_addr(); - - if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) - return -EACCES; /* Must turn broadcast on first */ - - sk->inuse = 1; - - /* Send the packet. */ - tmp = udp_send(sk, &sin, from, len, flags); - - /* The datagram has been sent off. Release the socket. */ - release_sock(sk); - return(tmp); -} - -/* - * In BSD SOCK_DGRAM a write is just like a send. - */ - -static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock, - unsigned flags) -{ - return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0)); -} - - -#ifndef _HURD_ -/* - * IOCTL requests applicable to the UDP protocol - */ - -int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - int err; - switch(cmd) - { - case TIOCOUTQ: - { - unsigned long amount; - - if (sk->state == TCP_LISTEN) return(-EINVAL); - amount = sk->prot->wspace(sk)/*/2*/; - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return(err); - put_fs_long(amount,(unsigned long *)arg); - return(0); - } - - case TIOCINQ: - { - struct sk_buff *skb; - unsigned long amount; - - if (sk->state == TCP_LISTEN) return(-EINVAL); - amount = 0; - skb = skb_peek(&sk->receive_queue); - if (skb != NULL) { - /* - * We will only return the amount - * of this packet since that is all - * that will be read. - */ - amount = skb->len; - } - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return(err); - put_fs_long(amount,(unsigned long *)arg); - return(0); - } - - default: - return(-EINVAL); - } - return(0); -} -#endif - -/* - * This should be easy, if there is something there we\ - * return it, otherwise we block. - */ - -int udp_recvfrom(struct sock *sk, unsigned char *to, int len, - int noblock, unsigned flags, struct sockaddr_in *sin, - int *addr_len) -{ - int copied = 0; - int truesize; - struct sk_buff *skb; - int er; - - /* - * Check any passed addresses - */ - - if (addr_len) - *addr_len=sizeof(*sin); - - /* - * From here the generic datagram does a lot of the work. Come - * the finished NET3, it will do _ALL_ the work! - */ - - skb=skb_recv_datagram(sk,flags,noblock,&er); - if(skb==NULL) - return er; - - truesize = skb->len; - copied = min(len, truesize); - - /* - * FIXME : should use udp header size info value - */ - - skb_copy_datagram(skb,sizeof(struct udphdr),to,copied); - sk->stamp=skb->stamp; - - /* Copy the address. */ - if (sin) - { - sin->sin_family = AF_INET; - sin->sin_port = skb->h.uh->source; - sin->sin_addr.s_addr = skb->daddr; - } - - skb_free_datagram(skb); - release_sock(sk); - return(truesize); -} - -/* - * Read has the same semantics as recv in SOCK_DGRAM - */ - -int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock, - unsigned flags) -{ - return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); -} - - -int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) -{ - struct rtable *rt; - unsigned long sa; - if (addr_len < sizeof(*usin)) - return(-EINVAL); - - if (usin->sin_family && usin->sin_family != AF_INET) - return(-EAFNOSUPPORT); - if (usin->sin_addr.s_addr==INADDR_ANY) - usin->sin_addr.s_addr=ip_my_addr(); - - if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) - return -EACCES; /* Must turn broadcast on first */ - - rt=ip_rt_route(usin->sin_addr.s_addr, NULL, &sa); - if(rt==NULL) - return -ENETUNREACH; - sk->saddr = sa; /* Update source address */ - sk->daddr = usin->sin_addr.s_addr; - sk->dummy_th.dest = usin->sin_port; - sk->state = TCP_ESTABLISHED; - return(0); -} - - -static void udp_close(struct sock *sk, int timeout) -{ - sk->inuse = 1; - sk->state = TCP_CLOSE; - if (sk->dead) - destroy_sock(sk); - else - release_sock(sk); -} - - -/* - * All we need to do is get the socket, and then do a checksum. - */ - -int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, - unsigned long daddr, unsigned short len, - unsigned long saddr, int redo, struct inet_protocol *protocol) -{ - struct sock *sk; - struct udphdr *uh; - unsigned short ulen; - int addr_type = IS_MYADDR; - - if(!dev || dev->pa_addr!=daddr) - addr_type=ip_chk_addr(daddr); - - /* - * Get the header. - */ - uh = (struct udphdr *) skb->h.uh; - - ip_statistics.IpInDelivers++; - - /* - * Validate the packet and the UDP length. - */ - - ulen = ntohs(uh->len); - - if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh)) - { - printk("UDP: short packet: %d/%d\n", ulen, len); - udp_statistics.UdpInErrors++; - kfree_skb(skb, FREE_WRITE); - return(0); - } - - if (uh->check && udp_check(uh, len, saddr, daddr)) - { - /* wants to know, who sent it, to - go and stomp on the garbage sender... */ - printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n", - ntohl(saddr),ntohs(uh->source), - ntohl(daddr),ntohs(uh->dest), - ulen); - udp_statistics.UdpInErrors++; - kfree_skb(skb, FREE_WRITE); - return(0); - } - - - len=ulen; - -#ifdef CONFIG_IP_MULTICAST - if (addr_type!=IS_MYADDR) - { - /* - * Multicasts and broadcasts go to each listener. - */ - struct sock *sknext=NULL; - sk=get_sock_mcast(udp_prot.sock_array[ntohs(uh->dest)&(SOCK_ARRAY_SIZE-1)], uh->dest, - saddr, uh->source, daddr); - if(sk) - { - do - { - struct sk_buff *skb1; - - sknext=get_sock_mcast(sk->next, uh->dest, saddr, uh->source, daddr); - if(sknext) - skb1=skb_clone(skb,GFP_ATOMIC); - else - skb1=skb; - if(skb1) - udp_deliver(sk, uh, skb1, dev,saddr,daddr,len); - sk=sknext; - } - while(sknext!=NULL); - } - else - kfree_skb(skb, FREE_READ); - return 0; - } -#endif - sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr); - if (sk == NULL) - { - udp_statistics.UdpNoPorts++; - if (addr_type == IS_MYADDR) - { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev); - } - /* - * Hmm. We got an UDP broadcast to a port to which we - * don't wanna listen. Ignore it. - */ - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - return(0); - } - - return udp_deliver(sk,uh,skb,dev, saddr, daddr, len); -} - -static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len) -{ - skb->sk = sk; - skb->dev = dev; - skb->len = len; - - /* - * These are supposed to be switched. - */ - - skb->daddr = saddr; - skb->saddr = daddr; - - - /* - * Charge it to the socket, dropping if the queue is full. - */ - - skb->len = len - sizeof(*uh); - - if (sock_queue_rcv_skb(sk,skb)<0) - { - udp_statistics.UdpInErrors++; - ip_statistics.IpInDiscards++; - ip_statistics.IpInDelivers--; - skb->sk = NULL; - kfree_skb(skb, FREE_WRITE); - release_sock(sk); - return(0); - } - udp_statistics.UdpInDatagrams++; - release_sock(sk); - return(0); -} - - -struct proto udp_prot = { - sock_wmalloc, - sock_rmalloc, - sock_wfree, - sock_rfree, - sock_rspace, - sock_wspace, - udp_close, - udp_read, - udp_write, - udp_sendto, - udp_recvfrom, - ip_build_header, - udp_connect, - NULL, - ip_queue_xmit, - NULL, - NULL, - NULL, - udp_rcv, - datagram_select, -#ifdef _HURD_ - NULL, -#else - udp_ioctl, -#endif - NULL, - NULL, - ip_setsockopt, - ip_getsockopt, - 128, - 0, - {NULL,}, - "UDP", - 0, 0 -}; - -static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr) -{ - unsigned long sum; - - __asm__( "\t addl %%ecx,%%ebx\n" - "\t adcl %%edx,%%ebx\n" - "\t adcl $0, %%ebx\n" - : "=b"(sum) - : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256) - : "cx","bx","dx" ); - - if (len > 3) - { - __asm__("\tclc\n" - "1:\n" - "\t lodsl\n" - "\t adcl %%eax, %%ebx\n" - "\t loop 1b\n" - "\t adcl $0, %%ebx\n" - : "=b"(sum) , "=S"(uh) - : "0"(sum), "c"(len/4) ,"1"(uh) - : "ax", "cx", "bx", "si" ); - } - - /* - * Convert from 32 bits to 16 bits. - */ - - __asm__("\t movl %%ebx, %%ecx\n" - "\t shrl $16,%%ecx\n" - "\t addw %%cx, %%bx\n" - "\t adcw $0, %%bx\n" - : "=b"(sum) - : "0"(sum) - : "bx", "cx"); - - /* - * Check for an extra word. - */ - - if ((len & 2) != 0) - { - __asm__("\t lodsw\n" - "\t addw %%ax,%%bx\n" - "\t adcw $0, %%bx\n" - : "=b"(sum), "=S"(uh) - : "0"(sum) ,"1"(uh) - : "si", "ax", "bx"); - } - - /* - * Now check for the extra byte. - */ - - if ((len & 1) != 0) - { - __asm__("\t lodsb\n" - "\t movb $0,%%ah\n" - "\t addw %%ax,%%bx\n" - "\t adcw $0, %%bx\n" - : "=b"(sum) - : "0"(sum) ,"S"(uh) - : "si", "ax", "bx"); - } - - /* - * We only want the bottom 16 bits, but we never cleared the top 16. - */ - - return((~sum) & 0xffff); -} diff --git a/pfinet/linux-inet/udp.h b/pfinet/linux-inet/udp.h deleted file mode 100644 index 6bfbb3cb..00000000 --- a/pfinet/linux-inet/udp.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the UDP module. - * - * Version: @(#)udp.h 1.0.2 05/07/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : Turned on udp checksums. I don't want to - * chase 'memory corruption' bugs that aren't! - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UDP_H -#define _UDP_H - -#include - - -#define UDP_NO_CHECK 0 - - -extern struct proto udp_prot; - - -extern void udp_err(int err, unsigned char *header, unsigned long daddr, - unsigned long saddr, struct inet_protocol *protocol); -extern int udp_recvfrom(struct sock *sk, unsigned char *to, - int len, int noblock, unsigned flags, - struct sockaddr_in *sin, int *addr_len); -extern int udp_read(struct sock *sk, unsigned char *buff, - int len, int noblock, unsigned flags); -extern int udp_connect(struct sock *sk, - struct sockaddr_in *usin, int addr_len); -extern int udp_rcv(struct sk_buff *skb, struct device *dev, - struct options *opt, unsigned long daddr, - unsigned short len, unsigned long saddr, int redo, - struct inet_protocol *protocol); -extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); - - -#endif /* _UDP_H */ diff --git a/pfinet/linux-inet/utils.c b/pfinet/linux-inet/utils.c deleted file mode 100644 index 60bbb9f8..00000000 --- a/pfinet/linux-inet/utils.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Various kernel-resident INET utility functions; mainly - * for format conversion and debugging output. - * - * Version: @(#)utils.c 1.0.7 05/18/93 - * - * Author: Fred N. van Kempen, - * - * Fixes: - * Alan Cox : verify_area check. - * Alan Cox : removed old debugging. - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip.h" -#include "protocol.h" -#include "tcp.h" -#include - - -/* - * Display an IP address in readable format. - */ - -char *in_ntoa(unsigned long in) -{ - static char buff[18]; - char *p; - - p = (char *) ∈ - sprintf(buff, "%d.%d.%d.%d", - (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255)); - return(buff); -} - - -/* - * Convert an ASCII string to binary IP. - */ - -unsigned long in_aton(char *str) -{ - unsigned long l; - unsigned int val; - int i; - - l = 0; - for (i = 0; i < 4; i++) - { - l <<= 8; - if (*str != '\0') - { - val = 0; - while (*str != '\0' && *str != '.') - { - val *= 10; - val += *str - '0'; - str++; - } - l |= val; - if (*str != '\0') - str++; - } - } - return(htonl(l)); -} - diff --git a/pfinet/linux-src/include/linux/net.h b/pfinet/linux-src/include/linux/net.h index 63e996f9..da193dcc 100644 --- a/pfinet/linux-src/include/linux/net.h +++ b/pfinet/linux-src/include/linux/net.h @@ -65,8 +65,14 @@ struct socket unsigned long flags; struct proto_ops *ops; struct inode *inode; +#ifdef _HURD_ + uint_fast32_t refcnt; /* # of sock_user's pointing to this */ + mach_port_t identity; /* for io_identity */ + struct file; /* forward decl magic */ +#else struct fasync_struct *fasync_list; /* Asynchronous wake up list */ struct file *file; /* File back pointer for gc */ +#endif struct sock *sk; struct wait_queue *wait; @@ -103,12 +109,12 @@ struct proto_ops { int (*getsockopt) (struct socket *sock, int level, int optname, char *optval, int *optlen); int (*fcntl) (struct socket *sock, unsigned int cmd, - unsigned long arg); + unsigned long arg); int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm); int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm); }; -struct net_proto_family +struct net_proto_family { int family; int (*create)(struct socket *sock, int protocol); @@ -119,7 +125,7 @@ struct net_proto_family short encrypt_net; }; -struct net_proto +struct net_proto { const char *name; /* Protocol name */ void (*init_func)(struct net_proto *); /* Bootstrap */ diff --git a/pfinet/linux-src/include/linux/rtnetlink.h b/pfinet/linux-src/include/linux/rtnetlink.h index b339f652..2b5d6efa 100644 --- a/pfinet/linux-src/include/linux/rtnetlink.h +++ b/pfinet/linux-src/include/linux/rtnetlink.h @@ -49,7 +49,7 @@ #define RTM_MAX (RTM_BASE+31) -/* +/* Generic structure for encapsulation optional route information. It is reminiscent of sockaddr, but with sa_family replaced with attribute type. @@ -90,7 +90,7 @@ struct rtmsg unsigned char rtm_table; /* Routing table id */ unsigned char rtm_protocol; /* Routing protocol; see below */ - unsigned char rtm_scope; /* See below */ + unsigned char rtm_scope; /* See below */ unsigned char rtm_type; /* See below */ unsigned rtm_flags; @@ -636,15 +636,19 @@ extern __inline__ void rtnl_exunlock(void) extern __inline__ void rtnl_shlock(void) { +#ifndef _HURD_ while (atomic_read(&rtnl_rlockct)) sleep_on(&rtnl_wait); atomic_inc(&rtnl_rlockct); +#endif } extern __inline__ void rtnl_shunlock(void) { +#ifndef _HURD_ if (atomic_dec_and_test(&rtnl_rlockct)) wake_up(&rtnl_wait); +#endif } extern __inline__ void rtnl_exlock(void) diff --git a/pfinet/linux-src/net/core/dev.c b/pfinet/linux-src/net/core/dev.c index cc9584a1..1dba3926 100644 --- a/pfinet/linux-src/net/core/dev.c +++ b/pfinet/linux-src/net/core/dev.c @@ -115,7 +115,7 @@ const char *if_port_text[] = { * and the routines to invoke. * * Why 16. Because with 16 the only overlap we get on a hash of the - * low nibble of the protocol value is RARP/SNAP/X.25. + * low nibble of the protocol value is RARP/SNAP/X.25. * * 0800 IP * 0001 802.3 @@ -137,13 +137,13 @@ struct packet_type *ptype_all = NULL; /* Taps */ * Device list lock. Setting it provides that interface * will not disappear unexpectedly while kernel sleeps. */ - + atomic_t dev_lockct = ATOMIC_INIT(0); /* * Our notifier list */ - + static struct notifier_block *netdev_chain=NULL; /* @@ -189,7 +189,7 @@ int netdev_nit=0; * change it and subsequent readers will get broken packet. * --ANK (980803) */ - + void dev_add_pack(struct packet_type *pt) { int hash; @@ -207,7 +207,7 @@ void dev_add_pack(struct packet_type *pt) ptype_all=pt; } else - { + { hash=ntohs(pt->type)&15; pt->next = ptype_base[hash]; ptype_base[hash] = pt; @@ -218,7 +218,7 @@ void dev_add_pack(struct packet_type *pt) /* * Remove a protocol ID from the list. */ - + void dev_remove_pack(struct packet_type *pt) { struct packet_type **pt1; @@ -251,15 +251,15 @@ void dev_remove_pack(struct packet_type *pt) ******************************************************************************************/ -/* +/* * Find an interface by name. */ - + struct device *dev_get(const char *name) { struct device *dev; - for (dev = dev_base; dev != NULL; dev = dev->next) + for (dev = dev_base; dev != NULL; dev = dev->next) { if (strcmp(dev->name, name) == 0) return(dev); @@ -271,7 +271,7 @@ struct device * dev_get_by_index(int ifindex) { struct device *dev; - for (dev = dev_base; dev != NULL; dev = dev->next) + for (dev = dev_base; dev != NULL; dev = dev->next) { if (dev->ifindex == ifindex) return(dev); @@ -283,7 +283,7 @@ struct device *dev_getbyhwaddr(unsigned short type, char *ha) { struct device *dev; - for (dev = dev_base; dev != NULL; dev = dev->next) + for (dev = dev_base; dev != NULL; dev = dev->next) { if (dev->type == type && memcmp(dev->dev_addr, ha, dev->addr_len) == 0) @@ -311,7 +311,7 @@ int dev_alloc_name(struct device *dev, const char *name) } return -ENFILE; /* Over 100 of the things .. bail out! */ } - + struct device *dev_alloc(const char *name, int *err) { struct device *dev=kmalloc(sizeof(struct device)+16, GFP_KERNEL); @@ -340,7 +340,7 @@ void netdev_state_change(struct device *dev) /* * Find and possibly load an interface. */ - + #ifdef CONFIG_KMOD void dev_load(const char *name) @@ -363,9 +363,9 @@ static int default_rebuild_header(struct sk_buff *skb) } /* - * Prepare an interface for use. + * Prepare an interface for use. */ - + int dev_open(struct device *dev) { int ret = 0; @@ -380,15 +380,15 @@ int dev_open(struct device *dev) /* * Call device private open method */ - - if (dev->open) + + if (dev->open) ret = dev->open(dev); /* * If it went open OK then: */ - - if (ret == 0) + + if (ret == 0) { /* * nil rebuild_header routine, @@ -404,7 +404,7 @@ int dev_open(struct device *dev) dev->flags |= (IFF_UP | IFF_RUNNING); /* - * Initialize multicasting status + * Initialize multicasting status */ dev_mc_upload(dev); @@ -448,7 +448,7 @@ void dev_clear_fastroute(struct device *dev) /* * Completely shutdown an interface. */ - + int dev_close(struct device *dev) { if (!(dev->flags&IFF_UP)) @@ -462,7 +462,7 @@ int dev_close(struct device *dev) * Call the device specific close. This cannot fail. * Only if device is UP */ - + if (dev->stop) dev->stop(dev); @@ -513,7 +513,7 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct device *dev) struct packet_type *ptype; get_fast_time(&skb->stamp); - for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) + for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) { /* Never send packets back to the socket * they originated from - MvS (miquels@drinkel.ow.org) @@ -558,7 +558,7 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct device *dev) /* * Fast path for loopback frames. */ - + void dev_loopback_xmit(struct sk_buff *skb) { struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC); @@ -608,7 +608,7 @@ int dev_queue_xmit(struct sk_buff *skb) made by us here. */ if (dev->flags&IFF_UP) { - if (netdev_nit) + if (netdev_nit) dev_queue_xmit_nit(skb,dev); if (dev->hard_start_xmit(skb, dev) == 0) { end_bh_atomic(); @@ -723,7 +723,7 @@ static void dev_clear_backlog(struct device *dev) * * It looks better to use net_bh trick, at least * to be sure, that we keep interrupt latency really low. --ANK (980727) - */ + */ if (backlog.qlen) { start_bh_atomic(); @@ -751,7 +751,7 @@ static void dev_clear_backlog(struct device *dev) /* * Receive a packet from a device driver and queue it for the upper - * (protocol) levels. It always succeeds. + * (protocol) levels. It always succeeds. */ void netif_rx(struct sk_buff *skb) @@ -802,13 +802,13 @@ static inline void handle_bridge(struct sk_buff *skb, unsigned short type) * We pass the bridge a complete frame. This means * recovering the MAC header first. */ - + int offset; skb=skb_clone(skb, GFP_ATOMIC); - if(skb==NULL) + if(skb==NULL) return; - + offset=skb->data-skb->mac.raw; skb_push(skb,offset); /* Put header back on for bridge */ @@ -828,7 +828,7 @@ static inline void handle_bridge(struct sk_buff *skb, unsigned short type) * This is run as a bottom half after an interrupt handler that does * mark_bh(NET_BH); */ - + void net_bh(void) { struct packet_type *ptype; @@ -854,7 +854,7 @@ void net_bh(void) if (qdisc_head.forw != &qdisc_head) qdisc_run_queues(); - + /* * Any data left to process. This may occur because a * mark_bh() is done after we empty the queue including @@ -869,7 +869,7 @@ void net_bh(void) * disabling interrupts. */ - while (!skb_queue_empty(&backlog)) + while (!skb_queue_empty(&backlog)) { struct sk_buff * skb; @@ -904,7 +904,7 @@ void net_bh(void) /* * Bump the pointer to the next structure. - * + * * On entry to the protocol layer. skb->data and * skb->nh.raw point to the MAC and encapsulated data */ @@ -919,7 +919,7 @@ void net_bh(void) } /* - * Fetch the packet protocol ID. + * Fetch the packet protocol ID. */ type = skb->protocol; @@ -930,7 +930,7 @@ void net_bh(void) * bridging code (if this protocol is to be bridged). * If it is bridged then move on */ - handle_bridge(skb, type); + handle_bridge(skb, type); #endif /* @@ -953,7 +953,7 @@ void net_bh(void) } } - for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) + for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) { if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev)) { @@ -989,16 +989,16 @@ void net_bh(void) /* * Has an unknown packet has been received ? */ - + else { kfree_skb(skb); } } /* End of queue loop */ - + /* * We have emptied the queue */ - + /* * One last output flush. */ @@ -1067,9 +1067,9 @@ static int dev_ifname(struct ifreq *arg) int err; /* - * Fetch the caller's info block. + * Fetch the caller's info block. */ - + err = copy_from_user(&ifr, arg, sizeof(struct ifreq)); if (err) return -EFAULT; @@ -1100,9 +1100,9 @@ static int dev_ifconf(char *arg) int i; /* - * Fetch the caller's info block. + * Fetch the caller's info block. */ - + if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) return -EFAULT; @@ -1110,7 +1110,7 @@ static int dev_ifconf(char *arg) len = ifc.ifc_len; /* - * Loop over the interfaces, and write an info block for each. + * Loop over the interfaces, and write an info block for each. */ total = 0; @@ -1131,14 +1131,14 @@ static int dev_ifconf(char *arg) } /* - * All done. Write the updated control block back to the caller. + * All done. Write the updated control block back to the caller. */ ifc.ifc_len = total; if (copy_to_user(arg, &ifc, sizeof(struct ifconf))) - return -EFAULT; + return -EFAULT; - /* + /* * Both BSD and Solaris return 0 here, so we do too. */ return 0; @@ -1154,7 +1154,7 @@ static int sprintf_stats(char *buffer, struct device *dev) { struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL); int size; - + if (stats) size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", dev->name, @@ -1181,31 +1181,31 @@ static int sprintf_stats(char *buffer, struct device *dev) * Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface * to create /proc/net/dev */ - + int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { int len=0; off_t begin=0; off_t pos=0; int size; - + struct device *dev; - size = sprintf(buffer, + size = sprintf(buffer, "Inter-| Receive | Transmit\n" " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"); - + pos+=size; len+=size; - - for (dev = dev_base; dev != NULL; dev = dev->next) + + for (dev = dev_base; dev != NULL; dev = dev->next) { size = sprintf_stats(buffer+len, dev); len+=size; pos=begin+len; - + if(posoffset+length) break; } - + *start=buffer+(offset-begin); /* Start of wanted data */ len-=(offset-begin); /* Start slop */ if(len>length) @@ -1305,17 +1305,17 @@ int dev_get_wireless_info(char * buffer, char **start, off_t offset, off_t begin = 0; off_t pos = 0; int size; - + struct device * dev; size = sprintf(buffer, "Inter-|sta| Quality | Discarded packets\n" " face |tus|link level noise| nwid crypt misc\n"); - + pos+=size; len+=size; - for(dev = dev_base; dev != NULL; dev = dev->next) + for(dev = dev_base; dev != NULL; dev = dev->next) { size = sprintf_wireless_stats(buffer+len, dev); len+=size; @@ -1388,7 +1388,7 @@ int dev_change_flags(struct device *dev, unsigned flags) /* * Load in the correct multicast list now the flags have changed. - */ + */ dev_mc_upload(dev); @@ -1403,7 +1403,7 @@ int dev_change_flags(struct device *dev, unsigned flags) { ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); - if (ret == 0) + if (ret == 0) dev_mc_upload(dev); } @@ -1430,10 +1430,16 @@ int dev_change_flags(struct device *dev, unsigned flags) return ret; } +#ifdef _HURD_ + +#define dev_ioctl 0 + +#else + /* - * Perform the SIOCxIFxxx calls. + * Perform the SIOCxIFxxx calls. */ - + static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) { struct device *dev; @@ -1442,7 +1448,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) if ((dev = dev_get(ifr->ifr_name)) == NULL) return -ENODEV; - switch(cmd) + switch(cmd) { case SIOCGIFFLAGS: /* Get interface flags */ ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI)) @@ -1451,18 +1457,18 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) case SIOCSIFFLAGS: /* Set interface flags */ return dev_change_flags(dev, ifr->ifr_flags); - + case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr->ifr_metric = 0; return 0; - + case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ return -EOPNOTSUPP; - + case SIOCGIFMTU: /* Get the MTU of a device */ ifr->ifr_mtu = dev->mtu; return 0; - + case SIOCSIFMTU: /* Set the MTU of a device */ if (ifr->ifr_mtu == dev->mtu) return 0; @@ -1470,7 +1476,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) /* * MTU must be positive. */ - + if (ifr->ifr_mtu<=0) return -EINVAL; @@ -1488,7 +1494,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr->ifr_hwaddr.sa_family=dev->type; return 0; - + case SIOCSIFHWADDR: if(dev->set_mac_address==NULL) return -EOPNOTSUPP; @@ -1498,7 +1504,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) if (!err) notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return err; - + case SIOCSIFHWBROADCAST: if(ifr->ifr_hwaddr.sa_family!=dev->type) return -EINVAL; @@ -1514,12 +1520,12 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) ifr->ifr_map.dma=dev->dma; ifr->ifr_map.port=dev->if_port; return 0; - + case SIOCSIFMAP: if (dev->set_config) return dev->set_config(dev,&ifr->ifr_map); return -EOPNOTSUPP; - + case SIOCADDMULTI: if(dev->set_multicast_list==NULL || ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) @@ -1598,7 +1604,7 @@ int dev_ioctl(unsigned int cmd, void *arg) and requires shared lock, because it sleeps writing to user space. */ - + if (cmd == SIOCGIFCONF) { rtnl_shlock(); ret = dev_ifconf((char *) arg); @@ -1619,10 +1625,10 @@ int dev_ioctl(unsigned int cmd, void *arg) *colon = 0; /* - * See which interface the caller is talking about. + * See which interface the caller is talking about. */ - - switch(cmd) + + switch(cmd) { /* * These ioctl calls: @@ -1630,7 +1636,7 @@ int dev_ioctl(unsigned int cmd, void *arg) * - atomic and do not require locking. * - return a value */ - + case SIOCGIFFLAGS: case SIOCGIFMETRIC: case SIOCGIFMTU: @@ -1655,7 +1661,7 @@ int dev_ioctl(unsigned int cmd, void *arg) * - require strict serialization. * - do not return a value */ - + case SIOCSIFFLAGS: case SIOCSIFMETRIC: case SIOCSIFMTU: @@ -1674,7 +1680,7 @@ int dev_ioctl(unsigned int cmd, void *arg) ret = dev_ifsioc(&ifr, cmd); rtnl_unlock(); return ret; - + case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently do not support it */ @@ -1685,8 +1691,8 @@ int dev_ioctl(unsigned int cmd, void *arg) /* * Unknown or private ioctl. - */ - + */ + default: if (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) { @@ -1719,6 +1725,8 @@ int dev_ioctl(unsigned int cmd, void *arg) } } +#endif + int dev_new_index(void) { static int ifindex; @@ -1740,7 +1748,7 @@ int register_netdevice(struct device *dev) if (dev_boot_phase) { /* This is NOT bug, but I am not sure, that all the devices, initialized before netdev module is started - are sane. + are sane. Now they are chained to device boot list and probed later. If a module is initialized @@ -1838,7 +1846,7 @@ int unregister_netdevice(struct device *dev) /* * Initialize the DEV module. At boot time this walks the device list and - * unhooks any devices that fail to initialise (normally hardware not + * unhooks any devices that fail to initialise (normally hardware not * present) and leaves us with a valid list of present and active devices. * */ @@ -1892,17 +1900,17 @@ __initfunc(int net_dev_init(void)) /* * Initialise the packet receive queue. */ - + skb_queue_head_init(&backlog); - + /* * The bridge has to be up before the devices */ -#ifdef CONFIG_BRIDGE +#ifdef CONFIG_BRIDGE br_init(); -#endif - +#endif + /* * This is Very Ugly(tm). * @@ -1914,7 +1922,7 @@ __initfunc(int net_dev_init(void)) #endif #if defined(CONFIG_DMASCC) dmascc_init(); -#endif +#endif #if defined(CONFIG_BPQETHER) bpq_init(); #endif @@ -1952,13 +1960,13 @@ __initfunc(int net_dev_init(void)) * SLHC if present needs attaching so other people see it * even if not opened. */ - -#ifdef CONFIG_INET + +#ifdef CONFIG_INET #if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \ || defined(CONFIG_PPP) \ || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP)) slhc_install(); -#endif +#endif #endif #ifdef CONFIG_NET_PROFILE @@ -1980,14 +1988,14 @@ __initfunc(int net_dev_init(void)) while ((dev = *dp) != NULL) { dev->iflink = -1; - if (dev->init && dev->init(dev)) + if (dev->init && dev->init(dev)) { /* * It failed to come up. Unhook it. */ *dp = dev->next; synchronize_bh(); - } + } else { dp = &dev->next; diff --git a/pfinet/linux-src/net/ipv4/af_inet.c b/pfinet/linux-src/net/ipv4/af_inet.c index e37eb6bd..04e05107 100644 --- a/pfinet/linux-src/net/ipv4/af_inet.c +++ b/pfinet/linux-src/net/ipv4/af_inet.c @@ -23,10 +23,10 @@ * when accept() ed * Alan Cox : Semantics of SO_LINGER aren't state moved * to close when you look carefully. With - * this fixed and the accept bug fixed + * this fixed and the accept bug fixed * some RPC stuff seems happier. * Niibe Yutaka : 4.4BSD style write async I/O - * Alan Cox, + * Alan Cox, * Tony Gale : Fixed reuse semantics. * Alan Cox : bind() shouldn't abort existing but dead * sockets. Stops FTP netin:.. I hope. @@ -141,7 +141,7 @@ int (*rarp_ioctl_hook)(unsigned int,void*) = NULL; /* * Destroy an AF_INET socket */ - + static __inline__ void kill_sk_queues(struct sock *sk) { struct sk_buff *skb; @@ -177,12 +177,12 @@ static __inline__ void kill_sk_later(struct sock *sk) { /* this should never happen. */ /* actually it can if an ack has just been sent. */ - /* + /* * It's more normal than that... * It can happen because a skb is still in the device queues * [PR] */ - + NETDEBUG(printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n", atomic_read(&sk->rmem_alloc), atomic_read(&sk->wmem_alloc))); @@ -223,12 +223,12 @@ void destroy_sock(struct sock *sk) * socket object. Mostly it punts to the subprotocols of IP to do * the work. */ - + /* * Set socket options on an inet socket. */ - + int inet_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { @@ -275,7 +275,7 @@ static int inet_autobind(struct sock *sk) /* * Move a socket into listening state. */ - + int inet_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; @@ -330,7 +330,7 @@ static int inet_create(struct socket *sock, int protocol) /* Compatibility */ if (sock->type == SOCK_PACKET) { - static int warned; + static int warned; if (net_families[PF_PACKET]==NULL) { #if defined(CONFIG_KMOD) && defined(CONFIG_PACKET_MODULE) @@ -348,7 +348,7 @@ static int inet_create(struct socket *sock, int protocol) sock->state = SS_UNCONNECTED; sk = sk_alloc(PF_INET, GFP_KERNEL, 1); - if (sk == NULL) + if (sk == NULL) goto do_oom; switch (sock->type) { @@ -392,13 +392,13 @@ static int inet_create(struct socket *sock, int protocol) } sock_init_data(sock,sk); - + sk->destruct = NULL; sk->zapped=0; #ifdef CONFIG_TCP_NAGLE_OFF sk->nonagle = 1; -#endif +#endif sk->family = PF_INET; sk->protocol = protocol; @@ -414,7 +414,7 @@ static int inet_create(struct socket *sock, int protocol) sk->ip_mc_ttl=1; sk->ip_mc_index=0; sk->ip_mc_list=NULL; - + if (sk->num) { /* It assumes that any protocol which allows * the user to assign a number at socket @@ -459,7 +459,7 @@ do_oom: * function we are destroying the object and from then on nobody * should refer to it. */ - + int inet_release(struct socket *sock, struct socket *peersock) { struct sock *sk = sock->sk; @@ -505,13 +505,13 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) /* If the socket has its own bind function then use it. (RAW) */ if(sk->prot->bind) return sk->prot->bind(sk, uaddr, addr_len); - + /* Check these errors (active socket, bad address length, double bind). */ if ((sk->state != TCP_CLOSE) || (addr_len < sizeof(struct sockaddr_in)) || (sk->num != 0)) return -EINVAL; - + chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); if (addr->sin_addr.s_addr != 0 && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) { @@ -538,10 +538,10 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) /* The kernel masquerader needs some ports. */ if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END)) return -EADDRINUSE; -#endif +#endif if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return(-EACCES); - + /* Make sure we are allowed to bind here. */ if (sk->prot->get_port(sk, snum) != 0) return -EADDRINUSE; @@ -564,10 +564,10 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, if (inet_autobind(sk) != 0) return(-EAGAIN); - if (sk->prot->connect == NULL) + if (sk->prot->connect == NULL) return(-EOPNOTSUPP); err = sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len); - if (err < 0) + if (err < 0) return(err); return(0); } @@ -594,7 +594,7 @@ static void inet_wait_for_connect(struct sock *sk) * Connect to a remote host. There is regrettably still a little * TCP 'magic' in here. */ - + int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags) { @@ -609,7 +609,7 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, if(sock->state == SS_CONNECTING) { /* Note: tcp_connected contains SYN_RECV, which may cause - bogus results here. -AK */ + bogus results here. -AK */ if(tcp_connected(sk->state)) { sock->state = SS_CONNECTED; return 0; @@ -619,7 +619,7 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, if (flags & O_NONBLOCK) return -EALREADY; } else { - if (sk->prot->connect == NULL) + if (sk->prot->connect == NULL) return(-EOPNOTSUPP); /* We may need to bind the socket. */ @@ -635,11 +635,11 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, return(err); sock->state = SS_CONNECTING; } - + if (sk->state > TCP_FIN_WAIT2 && sock->state == SS_CONNECTING) goto sock_error; - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return (-EINPROGRESS); if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) { @@ -650,15 +650,15 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, sock->state = SS_CONNECTED; if ((sk->state != TCP_ESTABLISHED) && sk->err) - goto sock_error; + goto sock_error; return(0); -sock_error: +sock_error: /* This is ugly but needed to fix a race in the ICMP error handler */ - if (sk->zapped && sk->state != TCP_CLOSE) { - lock_sock(sk); + if (sk->zapped && sk->state != TCP_CLOSE) { + lock_sock(sk); tcp_set_state(sk, TCP_CLOSE); - release_sock(sk); + release_sock(sk); sk->zapped = 0; } sock->state = SS_UNCONNECTED; @@ -735,16 +735,16 @@ do_err: /* * This does both peername and sockname. */ - + static int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sock *sk = sock->sk; struct sockaddr_in *sin = (struct sockaddr_in *)uaddr; - + sin->sin_family = AF_INET; if (peer) { - if (!tcp_connected(sk->state)) + if (!tcp_connected(sk->state)) return(-ENOTCONN); sin->sin_port = sk->dport; sin->sin_addr.s_addr = sk->daddr; @@ -767,10 +767,10 @@ int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size, struct sock *sk = sock->sk; int addr_len = 0; int err; - + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); - if (sk->prot->recvmsg == NULL) + if (sk->prot->recvmsg == NULL) return(-EOPNOTSUPP); /* We may need to bind the socket. */ if (inet_autobind(sk) != 0) @@ -793,7 +793,7 @@ int inet_sendmsg(struct socket *sock, struct msghdr *msg, int size, send_sig(SIGPIPE, current, 1); return(-EPIPE); } - if (sk->prot->sendmsg == NULL) + if (sk->prot->sendmsg == NULL) return(-EOPNOTSUPP); if(sk->err) return sock_error(sk); @@ -822,7 +822,7 @@ int inet_shutdown(struct socket *sock, int how) return(-ENOTCONN); if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) sock->state = SS_CONNECTED; - if (!tcp_connected(sk->state)) + if (!tcp_connected(sk->state)) return(-ENOTCONN); sk->shutdown |= how; if (sk->prot->shutdown) @@ -842,6 +842,10 @@ unsigned int inet_poll(struct file * file, struct socket *sock, poll_table *wait return sk->prot->poll(file, sock, wait); } +#ifdef _HURD_ +#define inet_ioctl 0 +#else + /* * ioctl() calls you can issue on an INET socket. Most of these are * device configuration and stuff and very rarely used. Some ioctls @@ -858,14 +862,14 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) int err; int pid; - switch(cmd) + switch(cmd) { case FIOSETOWN: case SIOCSPGRP: err = get_user(pid, (int *) arg); if (err) - return err; - if (current->pid != pid && current->pgrp != -pid && + return err; + if (current->pid != pid && current->pgrp != -pid && !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; @@ -905,18 +909,18 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCSIFNETMASK: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: - case SIOCSIFPFLAGS: - case SIOCGIFPFLAGS: + case SIOCSIFPFLAGS: + case SIOCGIFPFLAGS: case SIOCSIFFLAGS: return(devinet_ioctl(cmd,(void *) arg)); case SIOCGIFBR: case SIOCSIFBR: -#ifdef CONFIG_BRIDGE +#ifdef CONFIG_BRIDGE return(br_ioctl(cmd,(void *) arg)); #else return -ENOPKG; -#endif - +#endif + case SIOCADDDLCI: case SIOCDELDLCI: #ifdef CONFIG_DLCI @@ -946,13 +950,15 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) #endif if (sk->prot->ioctl==NULL || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD) - return(dev_ioctl(cmd,(void *) arg)); + return(dev_ioctl(cmd,(void *) arg)); return err; } /*NOTREACHED*/ return(0); } +#endif + struct proto_ops inet_stream_ops = { PF_INET, @@ -962,7 +968,7 @@ struct proto_ops inet_stream_ops = { inet_stream_connect, sock_no_socketpair, inet_accept, - inet_getname, + inet_getname, inet_poll, inet_ioctl, inet_listen, @@ -983,7 +989,7 @@ struct proto_ops inet_dgram_ops = { inet_dgram_connect, sock_no_socketpair, sock_no_accept, - inet_getname, + inet_getname, datagram_poll, inet_ioctl, sock_no_listen, @@ -1053,9 +1059,9 @@ extern void tcp_v4_init(struct net_proto_family *); /* - * Called by socket.c on kernel startup. + * Called by socket.c on kernel startup. */ - + __initfunc(void inet_proto_init(struct net_proto *pro)) { struct sk_buff *dummy_skb; @@ -1070,17 +1076,17 @@ __initfunc(void inet_proto_init(struct net_proto *pro)) } /* - * Tell SOCKET that we are alive... + * Tell SOCKET that we are alive... */ - + (void) sock_register(&inet_family_ops); /* - * Add all the protocols. + * Add all the protocols. */ printk(KERN_INFO "IP Protocols: "); - for(p = inet_protocol_base; p != NULL;) + for(p = inet_protocol_base; p != NULL;) { struct inet_protocol *tmp = (struct inet_protocol *) p->next; inet_add_protocol(p); @@ -1132,7 +1138,7 @@ __initfunc(void inet_proto_init(struct net_proto *pro)) #ifdef CONFIG_IP_MASQUERADE ip_masq_init(); #endif - + /* * Initialise the multicast router */ diff --git a/pfinet/linux-src/net/ipv4/arp.c b/pfinet/linux-src/net/ipv4/arp.c index 27d2f802..045513a8 100644 --- a/pfinet/linux-src/net/ipv4/arp.c +++ b/pfinet/linux-src/net/ipv4/arp.c @@ -15,9 +15,9 @@ * 2 of the License, or (at your option) any later version. * * Fixes: - * Alan Cox : Removed the Ethernet assumptions in + * Alan Cox : Removed the Ethernet assumptions in * Florian's code - * Alan Cox : Fixed some small errors in the ARP + * Alan Cox : Fixed some small errors in the ARP * logic * Alan Cox : Allow >4K in /proc * Alan Cox : Make ARP add its own protocol entry @@ -39,18 +39,18 @@ * Jonathan Naylor : Only lookup the hardware address for * the correct hardware type. * Germano Caronni : Assorted subtle races. - * Craig Schlenter : Don't modify permanent entry + * Craig Schlenter : Don't modify permanent entry * during arp_rcv. * Russ Nelson : Tidied up a few bits. * Alexey Kuznetsov: Major changes to caching and behaviour, - * eg intelligent arp probing and + * eg intelligent arp probing and * generation * of host down events. * Alan Cox : Missing unlock in device events. * Eckes : ARP ioctl control errors. * Alexey Kuznetsov: Arp free fix. * Manuel Rodriguez: Gratuitous ARP. - * Jonathan Layes : Added arpd support through kerneld + * Jonathan Layes : Added arpd support through kerneld * message queue (960314) * Mike Shaver : /proc/sys/net/ipv4/arp_* support * Mike McLagan : Routing by source @@ -77,7 +77,7 @@ unresolved IP address. (OK) 950727 -- MS */ - + #include #include #include @@ -257,7 +257,7 @@ static int arp_constructor(struct neighbour *neigh) switch (dev->type) { default: break; - case ARPHRD_ROSE: + case ARPHRD_ROSE: #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) case ARPHRD_AX25: #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) @@ -419,8 +419,8 @@ int arp_bind_neighbour(struct dst_entry *dst) * message. */ -void arp_send(int type, int ptype, u32 dest_ip, - struct device *dev, u32 src_ip, +void arp_send(int type, int ptype, u32 dest_ip, + struct device *dev, u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *target_hw) { @@ -431,14 +431,14 @@ void arp_send(int type, int ptype, u32 dest_ip, /* * No arp on this interface. */ - + if (dev->flags&IFF_NOARP) return; /* * Allocate a buffer */ - + skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + dev->hard_header_len + 15, GFP_ATOMIC); if (skb == NULL) @@ -544,10 +544,10 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) * of the device. Similarly, the hardware types should match. The * device should be ARP-able. Also, if pln is not 4, then the lookup * is not from an IP number. We can't currently handle this, so toss - * it. - */ + * it. + */ if (in_dev == NULL || - arp->ar_hln != dev->addr_len || + arp->ar_hln != dev->addr_len || dev->flags & IFF_NOARP || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || @@ -555,7 +555,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) goto out; switch (dev_type) { - default: + default: if (arp->ar_pro != __constant_htons(ETH_P_IP)) goto out; if (htons(dev_type) != arp->ar_hrd) @@ -622,7 +622,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) tha=arp_ptr; arp_ptr += dev->addr_len; memcpy(&tip, arp_ptr, 4); -/* +/* * Check for bad requests for 127.x.x.x and requests for multicast * addresses. If this is one such, delete it. */ @@ -633,16 +633,16 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) * Process entry. The idea here is we want to send a reply if it is a * request for us or if it is a request for someone else that we hold * a proxy for. We want to add an entry to our cache if it is a reply - * to us or if it is a request for our address. - * (The assumption for this last is that if someone is requesting our - * address, they are probably intending to talk to us, so it saves time - * if we cache their address. Their address is also probably not in + * to us or if it is a request for our address. + * (The assumption for this last is that if someone is requesting our + * address, they are probably intending to talk to us, so it saves time + * if we cache their address. Their address is also probably not in * our cache, since ours is not in their cache.) - * + * * Putting this another way, we only care about replies if they are to * us, in which case we add them to the cache. For requests, we care * about those for us and those for our proxies. We reply to both, - * and in the case of requests for us we add the requester to the arp + * and in the case of requests for us we add the requester to the arp * cache. */ @@ -781,7 +781,7 @@ int arp_req_set(struct arpreq *r, struct device * dev) if (!dev) return -EINVAL; } - if (r->arp_ha.sa_family != dev->type) + if (r->arp_ha.sa_family != dev->type) return -EINVAL; err = -ENOBUFS; @@ -878,6 +878,9 @@ int arp_req_delete(struct arpreq *r, struct device * dev) return err; } +#ifdef _HURD_ +#define arp_ioctl 0 +#else /* * Handle an ARP layer I/O control request. */ @@ -945,6 +948,7 @@ out: rtnl_unlock(); return err; } +#endif /* * Write the contents of the ARP cache to a PROCfs file. @@ -998,7 +1002,7 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy hbuffer[k++]=':'; } hbuffer[--k]=0; - + #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) } #endif @@ -1015,7 +1019,7 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy "%-17s0x%-10x0x%-10x%s", in_ntoa(*(u32*)n->primary_key), hatype, - arp_state_to_flags(n), + arp_state_to_flags(n), hbuffer); size += sprintf(buffer+len+size, " %-17s %s\n", @@ -1023,7 +1027,7 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy len += size; pos += size; - + if (pos <= offset) len=0; if (pos >= offset+length) @@ -1049,7 +1053,7 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy len += size; pos += size; - + if (pos <= offset) len=0; if (pos >= offset+length) @@ -1059,7 +1063,7 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy done: neigh_table_unlock(&arp_tbl); - + *start = buffer+len-(pos-offset); /* Start of wanted data */ len = pos-offset; /* Start slop */ if (len>length) @@ -1133,14 +1137,14 @@ char *ax2asc(ax25_address *a) if (c != ' ') *s++ = c; } - + *s++ = '-'; if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { *s++ = '1'; n -= 10; } - + *s++ = n + '0'; *s++ = '\0'; diff --git a/pfinet/linux-src/net/ipv4/devinet.c b/pfinet/linux-src/net/ipv4/devinet.c index a50ee3bd..ccae0c58 100644 --- a/pfinet/linux-src/net/ipv4/devinet.c +++ b/pfinet/linux-src/net/ipv4/devinet.c @@ -23,7 +23,7 @@ */ #include - + #include #include #include @@ -370,8 +370,8 @@ inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) #endif -/* - * Determine a default network mask, based on the IP address. +/* + * Determine a default network mask, based on the IP address. */ static __inline__ int inet_abc_len(u32 addr) @@ -380,21 +380,63 @@ static __inline__ int inet_abc_len(u32 addr) return 0; addr = ntohl(addr); - if (IN_CLASSA(addr)) + if (IN_CLASSA(addr)) return 8; - if (IN_CLASSB(addr)) + if (IN_CLASSB(addr)) return 16; - if (IN_CLASSC(addr)) + if (IN_CLASSC(addr)) return 24; /* - * Something else, probably a multicast. + * Something else, probably a multicast. */ - + return -1; } +#ifdef _HURD_ + +#define devinet_ioctl 0 + +error_t +configure_device (struct device *dev, + uint32_t addr, uint32_t netmask) +{ + struct in_device *in_dev = dev->ip_ptr; + struct in_ifaddr *ifa = in_dev ? in_dev->ifa_list : 0; + + if (ifa) + { + inet_del_ifa (in_dev, &in_dev->ifa_list, 0); + ifa->ifa_broadcast = 0; + ifa->ifa_anycast = 0; + } + else + { + ifa = inet_alloc_ifa (); + if (!ifa) + return ENOBUFS; + memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); + } + + if (addr != INADDR_NONE) + ifa->ifa_address = ifa->ifa_local = addr; + if (netmask != INADDR_NONE) + { + ifa->ifa_mask = netmask; + ifa->ifa_prefixlen = inet_mask_len (ifa->ifa_mask); + if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31) + ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask; + else + ifa->ifa_broadcast = 0; + } + + return - inet_set_ifa (dev, ifa); +} + +#else + int devinet_ioctl(unsigned int cmd, void *arg) { struct ifreq ifr; @@ -514,7 +556,7 @@ int devinet_ioctl(unsigned int cmd, void *arg) #endif ret = dev_change_flags(dev, ifr.ifr_flags); break; - + case SIOCSIFADDR: /* Set interface address (and family) */ if (inet_abc_len(sin->sin_addr.s_addr) < 0) { ret = -EINVAL; @@ -563,7 +605,7 @@ int devinet_ioctl(unsigned int cmd, void *arg) inet_insert_ifa(in_dev, ifa); } break; - + case SIOCSIFDSTADDR: /* Set the destination address */ if (ifa->ifa_address != sin->sin_addr.s_addr) { if (inet_abc_len(sin->sin_addr.s_addr) < 0) { @@ -605,6 +647,8 @@ rarok: return 0; } +#endif + static int inet_gifconf(struct device *dev, char *buf, int len) { @@ -657,7 +701,7 @@ u32 inet_select_addr(struct device *dev, u32 dst, int scope) if (!addr) addr = ifa->ifa_local; } endfor_ifa(in_dev); - + if (addr || scope >= RT_SCOPE_LINK) return addr; @@ -691,7 +735,7 @@ int unregister_inetaddr_notifier(struct notifier_block *nb) { return notifier_chain_unregister(&inetaddr_chain,nb); } - + static int inetdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct device *dev = ptr; @@ -725,7 +769,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, void case NETDEV_DOWN: ip_mc_down(in_dev); break; - case NETDEV_CHANGEMTU: + case NETDEV_CHANGEMTU: if (dev->mtu >= 68) break; /* MTU falled under minimal IP mtu. Disable IP. */ diff --git a/pfinet/linux-src/net/ipv4/tcp.c b/pfinet/linux-src/net/ipv4/tcp.c index 65763215..89e1bbbf 100644 --- a/pfinet/linux-src/net/ipv4/tcp.c +++ b/pfinet/linux-src/net/ipv4/tcp.c @@ -202,7 +202,7 @@ * Eric Schenk : Fix fast close down bug with * shutdown() followed by close(). * Andi Kleen : Make poll agree with SIGIO - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -249,8 +249,8 @@ * for violations and the like. tcp.c is just too big... If I say something * "does?" or "doesn't?", it means I'm not sure, and will have to hash it out * with Alan. -- MS 950903 - * [Note: Most of the TCP code has been rewriten/redesigned since this - * RFC1122 check. It is probably not correct anymore. It should be redone + * [Note: Most of the TCP code has been rewriten/redesigned since this + * RFC1122 check. It is probably not correct anymore. It should be redone * before 2.2. -AK] * * Use of PSH (4.2.2.2) @@ -384,14 +384,14 @@ * * ICMP messages (4.2.3.9) * MUST act on ICMP errors. (does) - * MUST slow transmission upon receipt of a Source Quench. (doesn't anymore + * MUST slow transmission upon receipt of a Source Quench. (doesn't anymore * because that is deprecated now by the IETF, can be turned on) * MUST NOT abort connection upon receipt of soft Destination * Unreachables (0, 1, 5), Time Exceededs and Parameter * Problems. (doesn't) * SHOULD report soft Destination Unreachables etc. to the * application. (does, except during SYN_RECV and may drop messages - * in some rare cases before accept() - ICMP is unreliable) + * in some rare cases before accept() - ICMP is unreliable) * SHOULD abort connection upon receipt of hard Destination Unreachable * messages (2, 3, 4). (does, but see above) * @@ -435,20 +435,20 @@ kmem_cache_t *tcp_timewait_cachep; * the socket locked or with interrupts disabled */ -static struct open_request *tcp_find_established(struct tcp_opt *tp, +static struct open_request *tcp_find_established(struct tcp_opt *tp, struct open_request **prevp) { struct open_request *req = tp->syn_wait_queue; - struct open_request *prev = (struct open_request *)&tp->syn_wait_queue; + struct open_request *prev = (struct open_request *)&tp->syn_wait_queue; while(req) { - if (req->sk && + if (req->sk && ((1 << req->sk->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))) break; - prev = req; + prev = req; req = req->dl_next; } - *prevp = prev; + *prevp = prev; return req; } @@ -539,7 +539,7 @@ static unsigned int tcp_listen_poll(struct sock *sk, poll_table *wait) } /* - * Compute minimal free write space needed to queue new packets. + * Compute minimal free write space needed to queue new packets. */ #define tcp_min_write_space(__sk) \ (atomic_read(&(__sk)->wmem_alloc) / 2) @@ -605,12 +605,12 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait) /* * Socket write_space callback. - * This (or rather the sock_wake_async) should agree with poll. + * This (or rather the sock_wake_async) should agree with poll. */ void tcp_write_space(struct sock *sk) { if (sk->dead) - return; + return; wake_up_interruptible(sk->sleep); if (sock_wspace(sk) >= @@ -619,6 +619,23 @@ void tcp_write_space(struct sock *sk) } +#ifdef _HURD_ + +#define tcp_ioctl 0 + +error_t +tcp_tiocinq(struct sock *sk, mach_msg_type_number_t *amount) +{ + if (sk->state == TCP_LISTEN) + return EINVAL; + lock_sock(sk); + *amount = tcp_readable(sk); + release_sock(sk); + return 0; +} + +#else + int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) { int answ; @@ -652,6 +669,8 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) return put_user(answ, (int *)arg); } +#endif + /* * Wait for a socket to get into the connected state * @@ -727,20 +746,20 @@ static void wait_for_tcp_memory(struct sock * sk) /* * Wait for a buffer. - */ -static int wait_for_buffer(struct sock *sk) -{ - struct wait_queue wait = { current, NULL }; - - release_sock(sk); - add_wait_queue(sk->sleep, &wait); - current->state = TASK_INTERRUPTIBLE; - schedule(); - current->state = TASK_RUNNING; + */ +static int wait_for_buffer(struct sock *sk) +{ + struct wait_queue wait = { current, NULL }; + + release_sock(sk); + add_wait_queue(sk->sleep, &wait); + current->state = TASK_INTERRUPTIBLE; + schedule(); + current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); - lock_sock(sk); - return 0; -} + lock_sock(sk); + return 0; +} /* When all user supplied data has been queued set the PSH bit */ #define PSH_NEEDED (seglen == 0 && iovlen == 0) @@ -781,7 +800,7 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg) iovlen = msg->msg_iovlen; iov = msg->msg_iov; copied = 0; - + while(--iovlen >= 0) { int seglen=iov->iov_len; unsigned char * from=iov->iov_base; @@ -801,7 +820,7 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg) /* Make sure that we are established. */ if (sk->shutdown & SEND_SHUTDOWN) goto do_shutdown; - + /* Now we need to check if we have a half * built packet we can tack some data onto. */ @@ -809,7 +828,7 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg) skb = sk->write_queue.prev; copy = skb->len; /* If the remote does SWS avoidance we should - * queue the best we can if not we should in + * queue the best we can if not we should in * fact send multiple packets... * A method for detecting this would be most * welcome. @@ -819,21 +838,21 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg) tp->snd_nxt < TCP_SKB_CB(skb)->end_seq) { int last_byte_was_odd = (copy % 4); - /* + /* * Check for parallel writers sleeping in user access. - */ - if (tp->partial_writers++ > 0) { + */ + if (tp->partial_writers++ > 0) { wait_for_buffer(sk); tp->partial_writers--; - continue; + continue; } - + copy = mss_now - copy; if(copy > skb_tailroom(skb)) copy = skb_tailroom(skb); if(copy > seglen) copy = seglen; - + if(last_byte_was_odd) { if(copy_from_user(skb_put(skb, copy), from, copy)) @@ -846,7 +865,7 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg) from, skb_put(skb, copy), copy, skb->csum, &err); } - + /* * FIXME: the *_user functions should * return how much data was @@ -867,8 +886,8 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg) if (PSH_NEEDED) TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; - if (--tp->partial_writers > 0) - wake_up_interruptible(sk->sleep); + if (--tp->partial_writers > 0) + wake_up_interruptible(sk->sleep); continue; } @@ -1012,7 +1031,7 @@ out: * this with tcp_send_ack(). * This is called for delayed acks also. */ - + void tcp_read_wakeup(struct sock *sk) { /* If we're closed, don't send an ack, or we'll get a RST @@ -1028,7 +1047,7 @@ void tcp_read_wakeup(struct sock *sk) */ static int tcp_recv_urg(struct sock * sk, int nonblock, - struct msghdr *msg, int len, int flags, + struct msghdr *msg, int len, int flags, int *addr_len) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -1050,15 +1069,15 @@ static int tcp_recv_urg(struct sock * sk, int nonblock, lock_sock(sk); if (tp->urg_data & URG_VALID) { - int err = 0; + int err = 0; char c = tp->urg_data; if (!(flags & MSG_PEEK)) tp->urg_data = URG_READ; - + if(msg->msg_name) tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) - msg->msg_name); + msg->msg_name); if(addr_len) *addr_len = tp->af_specific->sockaddr_len; @@ -1075,8 +1094,8 @@ static int tcp_recv_urg(struct sock * sk, int nonblock, } else msg->msg_flags|=MSG_TRUNC; - - /* N.B. Is this right?? If len == 0 we didn't read any data */ + + /* N.B. Is this right?? If len == 0 we didn't read any data */ return err ? -EFAULT : 1; } release_sock(sk); @@ -1111,7 +1130,7 @@ static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb) static void cleanup_rbuf(struct sock *sk, int copied) { struct sk_buff *skb; - + /* NOTE! The socket must be locked, so that we don't get * a messed-up receive queue. */ @@ -1143,9 +1162,9 @@ static void cleanup_rbuf(struct sock *sk, int copied) /* - * This routine copies from a sock struct into the user buffer. + * This routine copies from a sock struct into the user buffer. */ - + int tcp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int nonblock, int flags, int *addr_len) { @@ -1155,7 +1174,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, u32 peek_seq; volatile u32 *seq; /* So gcc doesn't overoptimise */ unsigned long used; - int err = 0; + int err = 0; int target = 1; /* Read at least this many bytes */ if (sk->err) @@ -1176,20 +1195,20 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, seq = &tp->copied_seq; if (flags & MSG_PEEK) seq = &peek_seq; - + /* Handle the POSIX bogosity MSG_WAITALL. */ if (flags & MSG_WAITALL) target=len; add_wait_queue(sk->sleep, &wait); lock_sock(sk); - + /* * BUG BUG BUG - * This violates 1003.1g compliance. We must wait for + * This violates 1003.1g compliance. We must wait for * data to exist even if we read none! */ - + while (len > 0) { struct sk_buff * skb; u32 offset; @@ -1219,7 +1238,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, if (!skb) break; - /* Now that we have two receive queues this + /* Now that we have two receive queues this * shouldn't happen. */ if (before(*seq, TCP_SKB_CB(skb)->seq)) { @@ -1366,7 +1385,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, if(copied >= 0 && msg->msg_name) { tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) - msg->msg_name); + msg->msg_name); if(addr_len) *addr_len = tp->af_specific->sockaddr_len; } @@ -1483,13 +1502,13 @@ static void tcp_close_pending (struct sock *sk) while(req) { struct open_request *iter; - + if (req->sk) tcp_close(req->sk, 0); iter = req; req = req->dl_next; - + (*iter->class->destructor)(iter); tcp_dec_slow_timer(TCP_SLT_SYNACK); sk->ack_backlog--; @@ -1583,7 +1602,7 @@ void tcp_close(struct sock *sk, long timeout) tsk->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); - + lock_sock(sk); } @@ -1613,7 +1632,7 @@ static struct open_request * wait_for_connect(struct sock * sk, schedule(); lock_sock(sk); req = tcp_find_established(&(sk->tp_pinfo.af_tcp), pprev); - if (req) + if (req) break; if (signal_pending(current)) break; @@ -1636,7 +1655,7 @@ struct sock *tcp_accept(struct sock *sk, int flags) struct sock *newsk = NULL; int error; - lock_sock(sk); + lock_sock(sk); /* We need to make sure that this socket is listening, * and that it has something pending. @@ -1652,10 +1671,10 @@ struct sock *tcp_accept(struct sock *sk, int flags) error = EAGAIN; if (flags & O_NONBLOCK) goto out; - + error = ERESTARTSYS; req = wait_for_connect(sk, &prev); - if (!req) + if (!req) goto out; } @@ -1663,7 +1682,7 @@ struct sock *tcp_accept(struct sock *sk, int flags) newsk = req->sk; req->class->destructor(req); tcp_openreq_free(req); - sk->ack_backlog--; + sk->ack_backlog--; if(sk->keepopen) tcp_inc_slow_timer(TCP_SLT_KEEPALIVE); @@ -1673,26 +1692,26 @@ struct sock *tcp_accept(struct sock *sk, int flags) out: /* sk should be in LISTEN state, thus accept can use sk->err for * internal purposes without stomping one anyone's feed. - */ - sk->err = error; + */ + sk->err = error; release_sock(sk); return newsk; } /* - * Socket option code for TCP. + * Socket option code for TCP. */ - -int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, + +int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); int val; if (level != SOL_TCP) - return tp->af_specific->setsockopt(sk, level, optname, + return tp->af_specific->setsockopt(sk, level, optname, optval, optlen); - + if(optlen application (OK) @@ -399,7 +399,7 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk, * This routine is called by the ICMP module when it gets some * sort of error condition. If err < 0 then the socket should * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. + * it's just the icmp type << 8 | icmp code. * Header points to the ip header of the error packet. We move * on past this. Then (as it used to claim before adjustment) * header points to the first 8 bytes of the udp header. We need @@ -463,16 +463,16 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len) } /* - * Various people wanted BSD UDP semantics. Well they've come + * Various people wanted BSD UDP semantics. Well they've come * back out because they slow down response to stuff like dead * or unreachable name servers and they screw term users something - * chronic. Oh and it violates RFC1122. So basically fix your + * chronic. Oh and it violates RFC1122. So basically fix your * client code people. */ - + /* - * RFC1122: OK. Passes ICMP errors back to application, as per - * 4.1.3.3. After the comment above, that should be no surprise. + * RFC1122: OK. Passes ICMP errors back to application, as per + * 4.1.3.3. After the comment above, that should be no surprise. */ if (!harderr && !sk->ip_recverr) @@ -497,7 +497,7 @@ static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); } -struct udpfakehdr +struct udpfakehdr { struct udphdr uh; u32 saddr; @@ -512,8 +512,8 @@ struct udpfakehdr * card and provide an additional callback mode for direct user->board I/O * transfers. That one will be fun. */ - -static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) + +static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; if (offset==0) { @@ -522,7 +522,7 @@ static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned i return -EFAULT; ufh->wcheck = csum_partial((char *)ufh, sizeof(struct udphdr), ufh->wcheck); - ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr, + ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr, ntohs(ufh->uh.len), IPPROTO_UDP, ufh->wcheck); if (ufh->uh.check == 0) @@ -542,8 +542,8 @@ static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned i * CONFIG_FAST_NET set for >10Mb/second boards to activate this sort of coding. * Timing needed to verify if this is a valid decision. */ - -static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) + +static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; @@ -582,7 +582,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) if (len < 0 || len > 0xFFFF) return -EMSGSIZE; - /* + /* * Check the flags. */ @@ -600,9 +600,9 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) #endif /* - * Get and verify the address. + * Get and verify the address. */ - + if (msg->msg_name) { struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; if (msg->msg_namelen < sizeof(*usin)) @@ -673,7 +673,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) connected = 0; } tos = RT_TOS(sk->ip_tos); - if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || + if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || (ipc.opt && ipc.opt->is_strictroute)) { tos |= RTO_ONLINK; connected = 0; @@ -703,11 +703,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) (msg->msg_flags&MSG_PROXY ? RTO_TPROXY : 0) | #endif tos, ipc.oif); - if (err) + if (err) goto out; err = -EACCES; - if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) + if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) goto out; if (connected && sk->dst_cache == NULL) sk->dst_cache = dst_clone(&rt->u.dst); @@ -739,13 +739,19 @@ out: return err; } +#ifdef _HURD_ + +#define udp_ioctl 0 + +#else + /* * IOCTL requests applicable to the UDP protocol */ - + int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - switch(cmd) + switch(cmd) { case TIOCOUTQ: { @@ -782,6 +788,8 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return(0); } +#endif + #ifndef HAVE_CSUM_COPY_USER #undef CONFIG_UDP_DELAY_CSUM #endif @@ -809,7 +817,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; - + copied = skb->len - sizeof(struct udphdr); if (copied > len) { copied = len; @@ -824,7 +832,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); } else if (copied > msg->msg_iov[0].iov_len || (msg->msg_flags&MSG_TRUNC)) { - if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) + if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) goto csum_copy_err; err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); @@ -833,11 +841,11 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, err = 0; csum = csum_partial(skb->h.raw, sizeof(struct udphdr), skb->csum); - csum = csum_and_copy_to_user((char*)&skb->h.uh[1], msg->msg_iov[0].iov_base, + csum = csum_and_copy_to_user((char*)&skb->h.uh[1], msg->msg_iov[0].iov_base, copied, csum, &err); if (err) goto out_free; - if ((unsigned short)csum_fold(csum)) + if ((unsigned short)csum_fold(csum)) goto csum_copy_err; } #endif @@ -851,7 +859,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, /* * Check any passed addresses */ - if (addr_len) + if (addr_len) *addr_len=sizeof(*sin); sin->sin_family = AF_INET; @@ -878,7 +886,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, if (sk->ip_cmsg_flags) ip_cmsg_recv(msg, skb); err = copied; - + out_free: skb_free_datagram(sk, skb); out: @@ -889,11 +897,11 @@ csum_copy_err: udp_statistics.UdpInErrors++; skb_free_datagram(sk, skb); - /* + /* * Error for blocking case is chosen to masquerade * as some normal condition. */ - return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; + return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; #endif } @@ -903,14 +911,14 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) struct rtable *rt; int err; - - if (addr_len < sizeof(*usin)) + + if (addr_len < sizeof(*usin)) return(-EINVAL); /* * 1003.1g - break association. */ - + if (usin->sin_family==AF_UNSPEC) { sk->saddr=INADDR_ANY; @@ -922,7 +930,7 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return 0; } - if (usin->sin_family && usin->sin_family != AF_INET) + if (usin->sin_family && usin->sin_family != AF_INET) return(-EAFNOSUPPORT); dst_release(xchg(&sk->dst_cache, NULL)); @@ -1056,9 +1064,9 @@ int udp_chkaddr(struct sk_buff *skb) #endif /* - * All we need to do is get the socket, and then do a checksum. + * All we need to do is get the socket, and then do a checksum. */ - + int udp_rcv(struct sk_buff *skb, unsigned short len) { struct sock *sk; @@ -1076,7 +1084,7 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) /* * Get the header. */ - + uh = skb->h.uh; __skb_pull(skb, skb->h.raw - skb->data); @@ -1085,7 +1093,7 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) /* * Validate the packet and the UDP length. */ - + ulen = ntohs(uh->len); if (ulen > len || ulen < sizeof(*uh)) { @@ -1100,13 +1108,13 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) if (uh->check && (((skb->ip_summed==CHECKSUM_HW)&&udp_check(uh,ulen,saddr,daddr,skb->csum)) || ((skb->ip_summed==CHECKSUM_NONE) && - (udp_check(uh,ulen,saddr,daddr, csum_partial((char*)uh, ulen, 0)))))) + (udp_check(uh,ulen,saddr,daddr, csum_partial((char*)uh, ulen, 0)))))) goto csum_error; #else if (uh->check==0) skb->ip_summed = CHECKSUM_UNNECESSARY; else if (skb->ip_summed==CHECKSUM_HW) { - if (udp_check(uh,ulen,saddr,daddr,skb->csum)) + if (udp_check(uh,ulen,saddr,daddr,skb->csum)) goto csum_error; skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) @@ -1124,11 +1132,11 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) else #endif sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); - + if (sk == NULL) { #ifdef CONFIG_UDP_DELAY_CSUM if (skb->ip_summed != CHECKSUM_UNNECESSARY && - (unsigned short)csum_fold(csum_partial((char*)uh, ulen, skb->csum))) + (unsigned short)csum_fold(csum_partial((char*)uh, ulen, skb->csum))) goto csum_error; #endif udp_statistics.UdpNoPorts++; @@ -1145,9 +1153,9 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) return 0; csum_error: - /* - * RFC1122: OK. Discards the bad packet silently (as far as - * the network is concerned, anyway) as per 4.1.3.4 (MUST). + /* + * RFC1122: OK. Discards the bad packet silently (as far as + * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", NIPQUAD(saddr), diff --git a/pfinet/linux/autoconf.h b/pfinet/linux/autoconf.h deleted file mode 100644 index e69de29b..00000000 diff --git a/pfinet/linux/config.h b/pfinet/linux/config.h deleted file mode 100644 index e69de29b..00000000 diff --git a/pfinet/linux/errno.h b/pfinet/linux/errno.h deleted file mode 100644 index 7dab9bab..00000000 --- a/pfinet/linux/errno.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _HACK_ERRNO_H -#define _HACK_ERRNO_H - -#include - -#define ERESTARTSYS EINTR - -#endif diff --git a/pfinet/linux/etherdevice.h b/pfinet/linux/etherdevice.h deleted file mode 100644 index 41073fcb..00000000 --- a/pfinet/linux/etherdevice.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. NET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Ethernet handlers. - * - * Version: @(#)eth.h 1.0.4 05/13/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * - * Relocated to include/linux where it belongs by Alan Cox - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * WARNING: This move may well be temporary. This file will get merged with others RSN. - * - */ -#ifndef _LINUX_ETHERDEVICE_H -#define _LINUX_ETHERDEVICE_H - - -#include - -#ifdef __KERNEL__ -extern int eth_header(unsigned char *buff, struct device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len, - struct sk_buff *skb); -extern int eth_rebuild_header(void *buff, struct device *dev, - unsigned long raddr, struct sk_buff *skb); -extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev); - -#endif - -#endif /* _LINUX_ETHERDEVICE_H */ diff --git a/pfinet/linux/fcntl.h b/pfinet/linux/fcntl.h deleted file mode 100644 index cd304557..00000000 --- a/pfinet/linux/fcntl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/pfinet/linux/icmp.h b/pfinet/linux/icmp.h deleted file mode 100644 index 334c756d..00000000 --- a/pfinet/linux/icmp.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the ICMP protocol. - * - * Version: @(#)icmp.h 1.0.3 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_ICMP_H -#define _LINUX_ICMP_H - -#define ICMP_ECHOREPLY 0 /* Echo Reply */ -#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ -#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ -#define ICMP_REDIRECT 5 /* Redirect (change route) */ -#define ICMP_ECHO 8 /* Echo Request */ -#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ -#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ -#define ICMP_TIMESTAMP 13 /* Timestamp Request */ -#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ -#define ICMP_INFO_REQUEST 15 /* Information Request */ -#define ICMP_INFO_REPLY 16 /* Information Reply */ -#define ICMP_ADDRESS 17 /* Address Mask Request */ -#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ - - -/* Codes for UNREACH. */ -#define ICMP_NET_UNREACH 0 /* Network Unreachable */ -#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ -#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ -#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ -#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ -#define ICMP_SR_FAILED 5 /* Source Route failed */ -#define ICMP_NET_UNKNOWN 6 -#define ICMP_HOST_UNKNOWN 7 -#define ICMP_HOST_ISOLATED 8 -#define ICMP_NET_ANO 9 -#define ICMP_HOST_ANO 10 -#define ICMP_NET_UNR_TOS 11 -#define ICMP_HOST_UNR_TOS 12 - -/* Codes for REDIRECT. */ -#define ICMP_REDIR_NET 0 /* Redirect Net */ -#define ICMP_REDIR_HOST 1 /* Redirect Host */ -#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ -#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ - -/* Codes for TIME_EXCEEDED. */ -#define ICMP_EXC_TTL 0 /* TTL count exceeded */ -#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ - - -struct icmphdr { - unsigned char type; - unsigned char code; - unsigned short checksum; - union { - struct { - unsigned short id; - unsigned short sequence; - } echo; - unsigned long gateway; - } un; -}; - - -struct icmp_err { - int error; - unsigned fatal:1; -}; - - -#endif /* _LINUX_ICMP_H */ diff --git a/pfinet/linux/if.h b/pfinet/linux/if.h deleted file mode 100644 index cb6b4e05..00000000 --- a/pfinet/linux/if.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the INET interface module. - * - * Version: @(#)if.h 1.0.2 04/18/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988 - * Ross Biro, - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_H -#define _LINUX_IF_H - -#include /* for "caddr_t" et al */ -#include /* for "struct sockaddr" et al */ - -/* Standard interface flags. */ -#define IFF_UP 0x1 /* interface is up */ -#define IFF_BROADCAST 0x2 /* broadcast address valid */ -#define IFF_DEBUG 0x4 /* turn on debugging */ -#define IFF_LOOPBACK 0x8 /* is a loopback net */ -#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ -#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ -#define IFF_RUNNING 0x40 /* resources allocated */ -#define IFF_NOARP 0x80 /* no ARP protocol */ -#define IFF_PROMISC 0x100 /* receive all packets */ -/* Not supported */ -#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/ - -#define IFF_MASTER 0x400 /* master of a load balancer */ -#define IFF_SLAVE 0x800 /* slave of a load balancer */ - -#define IFF_MULTICAST 0x1000 /* Supports multicast */ - -/* - * The ifaddr structure contains information about one address - * of an interface. They are maintained by the different address - * families, are allocated and attached when an address is set, - * and are linked together so all addresses for an interface can - * be located. - */ - -struct ifaddr -{ - struct sockaddr ifa_addr; /* address of interface */ - union { - struct sockaddr ifu_broadaddr; - struct sockaddr ifu_dstaddr; - } ifa_ifu; - struct iface *ifa_ifp; /* back-pointer to interface */ - struct ifaddr *ifa_next; /* next address for interface */ -}; - -#define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */ -#define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */ - -/* - * Device mapping structure. I'd just gone off and designed a - * beautiful scheme using only loadable modules with arguments - * for driver options and along come the PCMCIA people 8) - * - * Ah well. The get() side of this is good for WDSETUP, and it'll - * be handy for debugging things. The set side is fine for now and - * being very small might be worth keeping for clean configuration. - */ - -struct ifmap -{ - unsigned long mem_start; - unsigned long mem_end; - unsigned short base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; - /* 3 bytes spare */ -}; - -/* - * Interface request structure used for socket - * ioctl's. All interface ioctl's must have parameter - * definitions which begin with ifr_name. The - * remainder may be interface specific. - */ - -struct ifreq -{ -#define IFHWADDRLEN 6 -#define IFNAMSIZ 16 - union - { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - char ifrn_hwaddr[IFHWADDRLEN]; /* Obsolete */ - } ifr_ifrn; - - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - int ifru_metric; - int ifru_mtu; - struct ifmap ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - caddr_t ifru_data; - } ifr_ifru; -}; - -#define ifr_name ifr_ifrn.ifrn_name /* interface name */ -#define old_ifr_hwaddr ifr_ifrn.ifrn_hwaddr /* interface hardware */ -#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ -#define ifr_addr ifr_ifru.ifru_addr /* address */ -#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ -#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ -#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ -#define ifr_flags ifr_ifru.ifru_flags /* flags */ -#define ifr_metric ifr_ifru.ifru_metric /* metric */ -#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ -#define ifr_map ifr_ifru.ifru_map /* device map */ -#define ifr_slave ifr_ifru.ifru_slave /* slave device */ -#define ifr_data ifr_ifru.ifru_data /* for use by interface */ - -/* - * Structure used in SIOCGIFCONF request. - * Used to retrieve interface configuration - * for machine (useful for programs which - * must know all networks accessible). - */ - -struct ifconf -{ - int ifc_len; /* size of buffer */ - union - { - caddr_t ifcu_buf; - struct ifreq *ifcu_req; - } ifc_ifcu; -}; -#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ -#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ - - -/* BSD UNIX expects to find these here, so here we go: */ -#include -#include - -#endif /* _NET_IF_H */ diff --git a/pfinet/linux/if_arp.h b/pfinet/linux/if_arp.h deleted file mode 100644 index 75f86b61..00000000 --- a/pfinet/linux/if_arp.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the ARP (RFC 826) protocol. - * - * Version: @(#)if_arp.h 1.0.1 04/16/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 - * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. - * Ross Biro, - * Fred N. van Kempen, - * Florian La Roche. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_ARP_H -#define _LINUX_IF_ARP_H - -/* ARP protocol HARDWARE identifiers. */ -#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ -#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ -#define ARPHRD_EETHER 2 /* Experimental Ethernet */ -#define ARPHRD_AX25 3 /* AX.25 Level 2 */ -#define ARPHRD_PRONET 4 /* PROnet token ring */ -#define ARPHRD_CHAOS 5 /* Chaosnet */ -#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet- huh? */ -#define ARPHRD_ARCNET 7 /* ARCnet */ -#define ARPHRD_APPLETLK 8 /* APPLEtalk */ -/* Dummy types for non ARP hardware */ -#define ARPHRD_SLIP 256 -#define ARPHRD_CSLIP 257 -#define ARPHRD_SLIP6 258 -#define ARPHRD_CSLIP6 259 -#define ARPHRD_RSRVD 260 /* Notional KISS type */ -#define ARPHRD_ADAPT 264 -#define ARPHRD_PPP 512 -#define ARPHRD_TUNNEL 768 /* IPIP tunnel */ - -/* ARP protocol opcodes. */ -#define ARPOP_REQUEST 1 /* ARP request */ -#define ARPOP_REPLY 2 /* ARP reply */ -#define ARPOP_RREQUEST 3 /* RARP request */ -#define ARPOP_RREPLY 4 /* RARP reply */ - - -/* ARP ioctl request. */ -struct arpreq { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ - struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ -}; - -/* ARP Flag values. */ -#define ATF_COM 0x02 /* completed entry (ha valid) */ -#define ATF_PERM 0x04 /* permanent entry */ -#define ATF_PUBL 0x08 /* publish entry */ -#define ATF_USETRAILERS 0x10 /* has requested trailers */ -#define ATF_NETMASK 0x20 /* want to use a netmask (only - for proxy entries) */ - -/* - * This structure defines an ethernet arp header. - */ - -struct arphdr -{ - unsigned short ar_hrd; /* format of hardware address */ - unsigned short ar_pro; /* format of protocol address */ - unsigned char ar_hln; /* length of hardware address */ - unsigned char ar_pln; /* length of protocol address */ - unsigned short ar_op; /* ARP opcode (command) */ - -#if 0 - /* - * Ethernet looks like this : This bit is variable sized however... - */ - unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ - unsigned char ar_sip[4]; /* sender IP address */ - unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ - unsigned char ar_tip[4]; /* target IP address */ -#endif - -}; - -#endif /* _LINUX_IF_ARP_H */ diff --git a/pfinet/linux/if_ether.h b/pfinet/linux/if_ether.h deleted file mode 100644 index b87b1785..00000000 --- a/pfinet/linux/if_ether.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the Ethernet IEEE 802.3 interface. - * - * Version: @(#)if_ether.h 1.0.1a 02/08/94 - * - * Author: Fred N. van Kempen, - * Donald Becker, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_ETHER_H -#define _LINUX_IF_ETHER_H - - -/* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble - and FCS/CRC (frame check sequence). */ -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ - - -/* These are the defined Ethernet Protocol ID's. */ -#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ -#define ETH_P_ECHO 0x0200 /* Ethernet Echo packet */ -#define ETH_P_PUP 0x0400 /* Xerox PUP packet */ -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_ARP 0x0806 /* Address Resolution packet */ -#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ -#define ETH_P_X25 0x0805 /* CCITT X.25 */ -#define ETH_P_ATALK 0x809B /* Appletalk DDP */ -#define ETH_P_IPX 0x8137 /* IPX over DIX */ -#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ -#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ -#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ -#define ETH_P_802_2 0x0004 /* 802.2 frames */ -#define ETH_P_SNAP 0x0005 /* Internal only */ -/* This is an Ethernet frame header. */ -struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_proto; /* packet type ID field */ -}; - -/* Ethernet statistics collection data. */ -struct enet_statistics{ - int rx_packets; /* total packets received */ - int tx_packets; /* total packets transmitted */ - int rx_errors; /* bad packets received */ - int tx_errors; /* packet transmit problems */ - int rx_dropped; /* no space in linux buffers */ - int tx_dropped; /* no space available in linux */ - int multicast; /* multicast packets received */ - int collisions; - - /* detailed rx_errors: */ - int rx_length_errors; - int rx_over_errors; /* receiver ring buff overflow */ - int rx_crc_errors; /* recved pkt with crc error */ - int rx_frame_errors; /* recv'd frame alignment error */ - int rx_fifo_errors; /* recv'r fifo overrun */ - int rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - int tx_aborted_errors; - int tx_carrier_errors; - int tx_fifo_errors; - int tx_heartbeat_errors; - int tx_window_errors; -}; - -#endif /* _LINUX_IF_ETHER_H */ diff --git a/pfinet/linux/igmp.h b/pfinet/linux/igmp.h deleted file mode 100644 index 6ca7e019..00000000 --- a/pfinet/linux/igmp.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Linux NET3: Internet Gateway Management Protocol [IGMP] - * - * Authors: - * Alan Cox - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _LINUX_IGMP_H -#define _LINUX_IGMP_H - -/* - * IGMP protocol structures - */ - -struct igmphdr -{ - unsigned char type; - unsigned char unused; - unsigned short csum; - unsigned long group; -}; - -#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */ -#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */ -#define IGMP_HOST_LEAVE_MESSAGE 0x17 /* An extra BSD seems to send */ - - /* 224.0.0.1 */ -#define IGMP_ALL_HOSTS htonl(0xE0000001L) - -/* - * struct for keeping the multicast list in - */ - -#ifdef __KERNEL__ -struct ip_mc_socklist -{ - unsigned long multiaddr[IP_MAX_MEMBERSHIPS]; /* This is a speed trade off */ - struct device *multidev[IP_MAX_MEMBERSHIPS]; -}; - -struct ip_mc_list -{ - struct device *interface; - unsigned long multiaddr; - struct ip_mc_list *next; - struct timer_list timer; - int tm_running; - int users; -}; - -extern struct ip_mc_list *ip_mc_head; - - -extern int igmp_rcv(struct sk_buff *, struct device *, struct options *, unsigned long, unsigned short, - unsigned long, int , struct inet_protocol *); -extern void ip_mc_drop_device(struct device *dev); -extern int ip_mc_join_group(struct sock *sk, struct device *dev, unsigned long addr); -extern int ip_mc_leave_group(struct sock *sk, struct device *dev,unsigned long addr); -extern void ip_mc_drop_socket(struct sock *sk); -#endif -#endif diff --git a/pfinet/linux/in.h b/pfinet/linux/in.h deleted file mode 100644 index 260020a6..00000000 --- a/pfinet/linux/in.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/pfinet/linux/inet.h b/pfinet/linux/inet.h deleted file mode 100644 index 27aa5521..00000000 --- a/pfinet/linux/inet.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _HACK_INET_H_ -#define _HACK_INET_H_ - -char *in_ntoa (u_long); - -#endif diff --git a/pfinet/linux/interrupt.h b/pfinet/linux/interrupt.h deleted file mode 100644 index 01f11a8c..00000000 --- a/pfinet/linux/interrupt.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _HACK_INTERRUPT_H_ -#define _HACK_INTERRUPT_H_ - -#include -#include "pfinet.h" - -#define NET_BH 1 - -extern void mark_bh (int); - -#endif diff --git a/pfinet/linux/ip.h b/pfinet/linux/ip.h deleted file mode 100644 index bcc1bdea..00000000 --- a/pfinet/linux/ip.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP protocol. - * - * Version: @(#)ip.h 1.0.2 04/28/93 - * - * Authors: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IP_H -#define _LINUX_IP_H - - -#define IPOPT_END 0 -#define IPOPT_NOOP 1 -#define IPOPT_SEC 130 -#define IPOPT_LSRR 131 -#define IPOPT_SSRR 137 -#define IPOPT_RR 7 -#define IPOPT_SID 136 -#define IPOPT_TIMESTAMP 68 - - -#define MAXTTL 255 - -struct timestamp { - __u8 len; - __u8 ptr; - union { -#if defined(__i386__) - __u8 flags:4, - overflow:4; -#elif defined(__mc68000__) - __u8 overflow:4, - flags:4; -#elif defined(__MIPSEL__) - __u8 flags:4, - overflow:4; -#elif defined(__MIPSEB__) - __u8 overflow:4, - flags:4; -#elif defined(__alpha__) - __u8 flags:4, - overflow:4; -#elif defined(__sparc__) - __u8 overflow:4, - flags:4; -#else -#error "Adjust this structure to match your CPU" -#endif - __u8 full_char; - } x; - __u32 data[9]; -}; - - -#define MAX_ROUTE 16 - -struct route { - char route_size; - char pointer; - unsigned long route[MAX_ROUTE]; -}; - - -struct options { - struct route record_route; - struct route loose_route; - struct route strict_route; - struct timestamp tstamp; - unsigned short security; - unsigned short compartment; - unsigned short handling; - unsigned short stream; - unsigned tcc; -}; - - -struct iphdr { -#if defined(__i386__) - __u8 ihl:4, - version:4; -#elif defined (__mc68000__) - __u8 version:4, - ihl:4; -#elif defined(__MIPSEL__) - __u8 ihl:4, - version:4; -#elif defined(__MIPSEB__) - __u8 version:4, - ihl:4; -#elif defined(__alpha__) - __u8 ihl:4, - version:4; -#elif defined (__sparc__) - __u8 version:4, - ihl:4; -#else -#error "Adjust this structure to match your CPU" -#endif - __u8 tos; - __u16 tot_len; - __u16 id; - __u16 frag_off; - __u8 ttl; - __u8 protocol; - __u16 check; - __u32 saddr; - __u32 daddr; - /*The options start here. */ -}; - - -#endif /* _LINUX_IP_H */ diff --git a/pfinet/linux/ip_fw.h b/pfinet/linux/ip_fw.h deleted file mode 100644 index f80cccbf..00000000 --- a/pfinet/linux/ip_fw.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * IP firewalling code. This is taken from 4.4BSD. Please note the - * copyright message below. As per the GPL it must be maintained - * and the licenses thus do not conflict. While this port is subject - * to the GPL I also place my modifications under the original - * license in recognition of the original copyright. - * - * Ported from BSD to Linux, - * Alan Cox 22/Nov/1994. - * Merged and included the FreeBSD-Current changes at Ugen's request - * (but hey it's a lot cleaner now). Ugen would prefer in some ways - * we waited for his final product but since Linux 1.2.0 is about to - * appear it's not practical - Read: It works, it's not clean but please - * don't consider it to be his standard of finished work. - * Alan. - * - * All the real work was done by ..... - */ - -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - */ - -/* - * Format of an IP firewall descriptor - * - * src, dst, src_mask, dst_mask are always stored in network byte order. - * flags and num_*_ports are stored in host byte order (of course). - * Port numbers are stored in HOST byte order. - */ - -#ifndef _IP_FW_H -#define _IP_FW_H - -struct ip_fw -{ - struct ip_fw *fw_next; /* Next firewall on chain */ - struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ - struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ - struct in_addr fw_via; /* IP address of interface "via" */ - unsigned short fw_flg; /* Flags word */ - unsigned short fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */ - /* in ports array (dst ports follow */ - /* src ports; max of 10 ports in all; */ - /* count of 0 means match all ports) */ -#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */ - unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ - unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */ -}; - -/* - * Values for "flags" field . - */ - -#define IP_FW_F_ALL 0x000 /* This is a universal packet firewall*/ -#define IP_FW_F_TCP 0x001 /* This is a TCP packet firewall */ -#define IP_FW_F_UDP 0x002 /* This is a UDP packet firewall */ -#define IP_FW_F_ICMP 0x003 /* This is a ICMP packet firewall */ -#define IP_FW_F_KIND 0x003 /* Mask to isolate firewall kind */ -#define IP_FW_F_ACCEPT 0x004 /* This is an accept firewall (as * - * opposed to a deny firewall)* - * */ -#define IP_FW_F_SRNG 0x008 /* The first two src ports are a min * - * and max range (stored in host byte * - * order). * - * */ -#define IP_FW_F_DRNG 0x010 /* The first two dst ports are a min * - * and max range (stored in host byte * - * order). * - * (ports[0] <= port <= ports[1]) * - * */ -#define IP_FW_F_PRN 0x020 /* In verbose mode print this firewall*/ -#define IP_FW_F_BIDIR 0x040 /* For bidirectional firewalls */ -#define IP_FW_F_TCPSYN 0x080 /* For tcp packets-check SYN only */ -#define IP_FW_F_ICMPRPL 0x100 /* Send back icmp unreachable packet */ -#define IP_FW_F_MASK 0x1FF /* All possible flag bits mask */ - -/* - * New IP firewall options for [gs]etsockopt at the RAW IP level. - * Unlike BSD Linux inherits IP options so you don't have to use - * a raw socket for this. Instead we check rights in the calls. - */ - -#define IP_FW_BASE_CTL 64 - -#define IP_FW_ADD_BLK (IP_FW_BASE_CTL) -#define IP_FW_ADD_FWD (IP_FW_BASE_CTL+1) -#define IP_FW_CHK_BLK (IP_FW_BASE_CTL+2) -#define IP_FW_CHK_FWD (IP_FW_BASE_CTL+3) -#define IP_FW_DEL_BLK (IP_FW_BASE_CTL+4) -#define IP_FW_DEL_FWD (IP_FW_BASE_CTL+5) -#define IP_FW_FLUSH_BLK (IP_FW_BASE_CTL+6) -#define IP_FW_FLUSH_FWD (IP_FW_BASE_CTL+7) -#define IP_FW_ZERO_BLK (IP_FW_BASE_CTL+8) -#define IP_FW_ZERO_FWD (IP_FW_BASE_CTL+9) -#define IP_FW_POLICY_BLK (IP_FW_BASE_CTL+10) -#define IP_FW_POLICY_FWD (IP_FW_BASE_CTL+11) - -#define IP_ACCT_ADD (IP_FW_BASE_CTL+16) -#define IP_ACCT_DEL (IP_FW_BASE_CTL+17) -#define IP_ACCT_FLUSH (IP_FW_BASE_CTL+18) -#define IP_ACCT_ZERO (IP_FW_BASE_CTL+19) - -struct ip_fwpkt -{ - struct iphdr fwp_iph; /* IP header */ - union { - struct tcphdr fwp_tcph; /* TCP header or */ - struct udphdr fwp_udph; /* UDP header */ - } fwp_protoh; - struct in_addr fwp_via; /* interface address */ -}; - -/* - * Main firewall chains definitions and global var's definitions. - */ - -#ifdef __KERNEL__ - -#include - -#ifdef CONFIG_IP_FIREWALL -extern struct ip_fw *ip_fw_blk_chain; -extern struct ip_fw *ip_fw_fwd_chain; -extern int ip_fw_blk_policy; -extern int ip_fw_fwd_policy; -extern int ip_fw_ctl(int, void *, int); -#endif -#ifdef CONFIG_IP_ACCT -extern struct ip_fw *ip_acct_chain; -extern void ip_acct_cnt(struct iphdr *, struct device *, struct ip_fw *); -extern int ip_acct_ctl(int, void *, int); -#endif -extern int ip_fw_chk(struct iphdr *, struct device *rif,struct ip_fw *, int, int); -#endif /* KERNEL */ - -#endif /* _IP_FW_H */ diff --git a/pfinet/linux/ipx.h b/pfinet/linux/ipx.h deleted file mode 100644 index d3bff83b..00000000 --- a/pfinet/linux/ipx.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef _IPX_H_ -#define _IPX_H_ -#include -#define IPX_NODE_LEN 6 -#define IPX_MTU 576 - -struct sockaddr_ipx -{ - short sipx_family; - short sipx_port; - unsigned long sipx_network; - unsigned char sipx_node[IPX_NODE_LEN]; - unsigned char sipx_type; - unsigned char sipx_zero; /* 16 byte fill */ -}; - -/* - * So we can fit the extra info for SIOCSIFADDR into the address nicely - */ - -#define sipx_special sipx_port -#define sipx_action sipx_zero -#define IPX_DLTITF 0 -#define IPX_CRTITF 1 - -typedef struct ipx_route_definition -{ - unsigned long ipx_network; - unsigned long ipx_router_network; - unsigned char ipx_router_node[IPX_NODE_LEN]; -} ipx_route_definition; - -typedef struct ipx_interface_definition -{ - unsigned long ipx_network; - unsigned char ipx_device[16]; - unsigned char ipx_dlink_type; -#define IPX_FRAME_NONE 0 -#define IPX_FRAME_SNAP 1 -#define IPX_FRAME_8022 2 -#define IPX_FRAME_ETHERII 3 -#define IPX_FRAME_8023 4 - unsigned char ipx_special; -#define IPX_SPECIAL_NONE 0 -#define IPX_PRIMARY 1 -#define IPX_INTERNAL 2 - unsigned char ipx_node[IPX_NODE_LEN]; -} ipx_interface_definition; - -typedef struct ipx_config_data -{ - unsigned char ipxcfg_auto_select_primary; - unsigned char ipxcfg_auto_create_interfaces; -} ipx_config_data; - -/* - * OLD Route Definition for backward compatibility. - */ - -struct ipx_route_def -{ - unsigned long ipx_network; - unsigned long ipx_router_network; -#define IPX_ROUTE_NO_ROUTER 0 - unsigned char ipx_router_node[IPX_NODE_LEN]; - unsigned char ipx_device[16]; - unsigned short ipx_flags; -#define IPX_RT_SNAP 8 -#define IPX_RT_8022 4 -#define IPX_RT_BLUEBOOK 2 -#define IPX_RT_ROUTED 1 -}; - -#define SIOCAIPXITFCRT (SIOCPROTOPRIVATE) -#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE+1) -#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE+2) -#endif - diff --git a/pfinet/linux/kernel.h b/pfinet/linux/kernel.h deleted file mode 100644 index dcd5acf3..00000000 --- a/pfinet/linux/kernel.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _HACK_KERNEL_H -#define _HACK_KERNEL_H - -#include -#include -#include -#include - -#define printk printf - -extern inline int -getname (const char *name, char **newp) -{ - *newp = malloc (strlen (name) + 1); - strcpy (*newp, name); - return 0; -} - -extern inline void -putname (char *p) -{ - free (p); -} - -/* These two functions are used only to send SIGURG. But I can't - find any SIGIO code at all. So we'll just punt on that; clearly - Linux is missing the point. SIGURG should only be sent for - sockets that have explicitly requested it. */ -extern inline int -kill_proc (int pid, int signo, int priv) -{ - assert (signo == SIGURG); - return 0; -} - -extern inline int -kill_pg (int pgrp, int signo, int priv) -{ - assert (signo == SIGURG); - return 0; -} - - -#endif diff --git a/pfinet/linux/major.h b/pfinet/linux/major.h deleted file mode 100644 index e69de29b..00000000 diff --git a/pfinet/linux/malloc.h b/pfinet/linux/malloc.h deleted file mode 100644 index 06930659..00000000 --- a/pfinet/linux/malloc.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _HACK_MALLOC_H_ -#define _HACK_MALLOC_H_ - -#include - -#define kfree_s(a,b) (free (a)) -#define kfree(a) (free (a)) -#define kmalloc(a,b) (malloc (a)) - -#endif diff --git a/pfinet/linux/mm.h b/pfinet/linux/mm.h deleted file mode 100644 index 0fb18a59..00000000 --- a/pfinet/linux/mm.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _HACK_MM_H_ -#define _HACK_MM_H_ - -#include -#include - -/* All memory addresses are presumptively valid, because they are - all internal. */ -#define verify_area(a,b,c) 0 - -#define VERIFY_READ 0 -#define VERIFY_WRITE 0 -#define GFP_ATOMIC 0 -#define GFP_KERNEL 0 - -#endif diff --git a/pfinet/linux/net.h b/pfinet/linux/net.h deleted file mode 100644 index 341d0253..00000000 --- a/pfinet/linux/net.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * NET An implementation of the SOCKET network access protocol. - * This is the master header file for the Linux NET layer, - * or, in plain English: the networking handling part of the - * kernel. - * - * Version: @(#)net.h 1.0.3 05/25/93 - * - * Authors: Orest Zborowski, - * Ross Biro, - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_NET_H -#define _LINUX_NET_H - - -#include -#include - - -#define NSOCKETS 2000 /* Dynamic, this is MAX LIMIT */ -#define NSOCKETS_UNIX 128 /* unix domain static limit */ -#define NPROTO 16 /* should be enough for now.. */ - - -#define SYS_SOCKET 1 /* sys_socket(2) */ -#define SYS_BIND 2 /* sys_bind(2) */ -#define SYS_CONNECT 3 /* sys_connect(2) */ -#define SYS_LISTEN 4 /* sys_listen(2) */ -#define SYS_ACCEPT 5 /* sys_accept(2) */ -#define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */ -#define SYS_GETPEERNAME 7 /* sys_getpeername(2) */ -#define SYS_SOCKETPAIR 8 /* sys_socketpair(2) */ -#define SYS_SEND 9 /* sys_send(2) */ -#define SYS_RECV 10 /* sys_recv(2) */ -#define SYS_SENDTO 11 /* sys_sendto(2) */ -#define SYS_RECVFROM 12 /* sys_recvfrom(2) */ -#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */ -#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */ -#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ - - -typedef enum { - SS_FREE = 0, /* not allocated */ - SS_UNCONNECTED, /* unconnected to any socket */ - SS_CONNECTING, /* in process of connecting */ - SS_CONNECTED, /* connected to socket */ - SS_DISCONNECTING /* in process of disconnecting */ -} socket_state; - -#define SO_ACCEPTCON (1<<16) /* performed a listen */ -#define SO_WAITDATA (1<<17) /* wait data to read */ -#define SO_NOSPACE (1<<18) /* no space to write */ - -#ifdef __KERNEL__ -/* - * Internal representation of a socket. not all the fields are used by - * all configurations: - * - * server client - * conn client connected to server connected to - * iconn list of clients -unused- - * awaiting connections - * wait sleep for clients, sleep for connection, - * sleep for i/o sleep for i/o - */ -struct socket { - short type; /* SOCK_STREAM, ... */ - socket_state state; - long flags; -#ifdef _HURD_ - int userflags; /* O_* */ - int refcnt; - mach_port_t identity; -#endif - struct proto_ops *ops; /* protocols do most everything */ - void *data; /* protocol data */ - struct socket *conn; /* server socket connected to */ - struct socket *iconn; /* incomplete client conn.s */ - struct socket *next; - struct wait_queue **wait; /* ptr to place to wait on */ - struct inode *inode; - struct fasync_struct *fasync_list; /* Asynchronous wake up list */ -}; - -#define SOCK_INODE(S) ((S)->inode) - -struct proto_ops { - int family; - - int (*create) (struct socket *sock, int protocol); - int (*dup) (struct socket *newsock, struct socket *oldsock); - int (*release) (struct socket *sock, struct socket *peer); - int (*bind) (struct socket *sock, struct sockaddr *umyaddr, - int sockaddr_len); - int (*connect) (struct socket *sock, struct sockaddr *uservaddr, - int sockaddr_len, int flags); - int (*socketpair) (struct socket *sock1, struct socket *sock2); - int (*accept) (struct socket *sock, struct socket *newsock, - int flags); - int (*getname) (struct socket *sock, struct sockaddr *uaddr, - int *usockaddr_len, int peer); - int (*read) (struct socket *sock, char *ubuf, int size, - int nonblock); - int (*write) (struct socket *sock, char *ubuf, int size, - int nonblock); - int (*select) (struct socket *sock, int sel_type, - select_table *wait); - int (*ioctl) (struct socket *sock, unsigned int cmd, - unsigned long arg); - int (*listen) (struct socket *sock, int len); - int (*send) (struct socket *sock, void *buff, int len, int nonblock, - unsigned flags); - int (*recv) (struct socket *sock, void *buff, int len, int nonblock, - unsigned flags); - int (*sendto) (struct socket *sock, void *buff, int len, int nonblock, - unsigned flags, struct sockaddr *, int addr_len); - int (*recvfrom) (struct socket *sock, void *buff, int len, int nonblock, - unsigned flags, struct sockaddr *, int *addr_len); - int (*shutdown) (struct socket *sock, int flags); - int (*setsockopt) (struct socket *sock, int level, int optname, - char *optval, int optlen); - int (*getsockopt) (struct socket *sock, int level, int optname, - char *optval, int *optlen); - int (*fcntl) (struct socket *sock, unsigned int cmd, - unsigned long arg); -}; - -struct net_proto { - char *name; /* Protocol name */ - void (*init_func)(struct net_proto *); /* Bootstrap */ -}; - -extern int sock_awaitconn(struct socket *mysock, struct socket *servsock, int flags); -extern int sock_wake_async(struct socket *sock, int how); -extern int sock_register(int family, struct proto_ops *ops); -extern int sock_unregister(int family); -extern struct socket *sock_alloc(void); -extern void sock_release(struct socket *sock); -#endif /* __KERNEL__ */ -#endif /* _LINUX_NET_H */ diff --git a/pfinet/linux/netdevice.h b/pfinet/linux/netdevice.h deleted file mode 100644 index dcca542d..00000000 --- a/pfinet/linux/netdevice.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Interfaces handler. - * - * Version: @(#)dev.h 1.0.10 08/12/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Corey Minyard - * Donald J. Becker, - * Alan Cox, - * Bjorn Ekwall. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Moved to /usr/include/linux for NET3 - */ -#ifndef _LINUX_NETDEVICE_H -#define _LINUX_NETDEVICE_H - -#include -#include -#include - -/* for future expansion when we will have different priorities. */ -#define DEV_NUMBUFFS 3 -#define MAX_ADDR_LEN 7 -#define MAX_HEADER 18 - -#define IS_MYADDR 1 /* address is (one of) our own */ -#define IS_LOOPBACK 2 /* address is for LOOPBACK */ -#define IS_BROADCAST 3 /* address is a valid broadcast */ -#define IS_INVBCAST 4 /* Wrong netmask bcast not for us (unused)*/ -#define IS_MULTICAST 5 /* Multicast IP address */ - -/* - * We tag these structures with multicasts. - */ - -struct dev_mc_list -{ - struct dev_mc_list *next; - char dmi_addr[MAX_ADDR_LEN]; - unsigned short dmi_addrlen; - unsigned short dmi_users; -}; - -/* - * The DEVICE structure. - * Actually, this whole structure is a big mistake. It mixes I/O - * data with strictly "high-level" data, and it has to know about - * almost every data structure used in the INET module. - */ -struct device -{ - - /* - * This is the first field of the "visible" part of this structure - * (i.e. as seen by users in the "Space.c" file). It is the name - * the interface. - */ - char *name; - - /* I/O specific fields - FIXME: Merge these and struct ifmap into one */ - unsigned long rmem_end; /* shmem "recv" end */ - unsigned long rmem_start; /* shmem "recv" start */ - unsigned long mem_end; /* sahared mem end */ - unsigned long mem_start; /* shared mem start */ - unsigned long base_addr; /* device I/O address */ - unsigned char irq; /* device IRQ number */ - - /* Low-level status flags. */ - volatile unsigned char start, /* start an operation */ - tbusy, /* transmitter busy */ - interrupt; /* interrupt arrived */ - - struct device *next; - - /* The device initialization function. Called only once. */ - int (*init)(struct device *dev); - - /* Some hardware also needs these fields, but they are not part of the - usual set specified in Space.c. */ - unsigned char if_port; /* Selectable AUI, TP,..*/ - unsigned char dma; /* DMA channel */ - - struct enet_statistics* (*get_stats)(struct device *dev); - - /* - * This marks the end of the "visible" part of the structure. All - * fields hereafter are internal to the system, and may change at - * will (read: may be cleaned up at will). - */ - - /* These may be needed for future network-power-down code. */ - unsigned long trans_start; /* Time (in jiffies) of last Tx */ - unsigned long last_rx; /* Time of last Rx */ - - unsigned short flags; /* interface flags (a la BSD) */ - unsigned short family; /* address family ID (AF_INET) */ - unsigned short metric; /* routing metric (not used) */ - unsigned short mtu; /* interface MTU value */ - unsigned short type; /* interface hardware type */ - unsigned short hard_header_len; /* hardware hdr length */ - void *priv; /* pointer to private data */ - - /* Interface address info. */ - unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ - unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ - unsigned char addr_len; /* hardware address length */ - unsigned long pa_addr; /* protocol address */ - unsigned long pa_brdaddr; /* protocol broadcast addr */ - unsigned long pa_dstaddr; /* protocol P-P other side addr */ - unsigned long pa_mask; /* protocol netmask */ - unsigned short pa_alen; /* protocol address length */ - - struct dev_mc_list *mc_list; /* Multicast mac addresses */ - int mc_count; /* Number of installed mcasts */ - - struct ip_mc_list *ip_mc_list; /* IP multicast filter chain */ - - /* For load balancing driver pair support */ - - unsigned long pkt_queue; /* Packets queued */ - struct device *slave; /* Slave device */ - - - /* Pointer to the interface buffers. */ - struct sk_buff_head buffs[DEV_NUMBUFFS]; - - /* Pointers to interface service routines. */ - int (*open)(struct device *dev); - int (*stop)(struct device *dev); - int (*hard_start_xmit) (struct sk_buff *skb, - struct device *dev); - int (*hard_header) (unsigned char *buff, - struct device *dev, - unsigned short type, - void *daddr, - void *saddr, - unsigned len, - struct sk_buff *skb); - int (*rebuild_header)(void *eth, struct device *dev, - unsigned long raddr, struct sk_buff *skb); - unsigned short (*type_trans) (struct sk_buff *skb, - struct device *dev); -#define HAVE_MULTICAST - void (*set_multicast_list)(struct device *dev, - int num_addrs, void *addrs); -#define HAVE_SET_MAC_ADDR - int (*set_mac_address)(struct device *dev, void *addr); -#define HAVE_PRIVATE_IOCTL - int (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd); -#define HAVE_SET_CONFIG - int (*set_config)(struct device *dev, struct ifmap *map); - -}; - - -struct packet_type { - unsigned short type; /* This is really htons(ether_type). */ - struct device * dev; - int (*func) (struct sk_buff *, struct device *, - struct packet_type *); - void *data; - struct packet_type *next; -}; - - -#ifdef __KERNEL__ - -#include - -/* Used by dev_rint */ -#define IN_SKBUFF 1 - -extern volatile char in_bh; - -extern struct device loopback_dev; -extern struct device *dev_base; -extern struct packet_type *ptype_base; - - -extern int ip_addr_match(unsigned long addr1, unsigned long addr2); -extern int ip_chk_addr(unsigned long addr); -extern struct device *ip_dev_check(unsigned long daddr); -extern unsigned long ip_my_addr(void); -extern unsigned long ip_get_mask(unsigned long addr); - -extern void dev_add_pack(struct packet_type *pt); -extern void dev_remove_pack(struct packet_type *pt); -extern struct device *dev_get(char *name); -extern int dev_open(struct device *dev); -extern int dev_close(struct device *dev); -extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev, - int pri); -#define HAVE_NETIF_RX 1 -extern void netif_rx(struct sk_buff *skb); -/* The old interface to netif_rx(). */ -extern int dev_rint(unsigned char *buff, long len, int flags, - struct device * dev); -extern void dev_transmit(void); -extern int in_net_bh(void); -extern void net_bh(void *tmp); -extern void dev_tint(struct device *dev); -extern int dev_get_info(char *buffer, char **start, off_t offset, int length); -extern int dev_ioctl(unsigned int cmd, void *); - -extern void dev_init(void); - -/* These functions live elsewhere (drivers/net/net_init.c, but related) */ - -extern void ether_setup(struct device *dev); -extern int ether_config(struct device *dev, struct ifmap *map); -/* Support for loadable net-drivers */ -extern int register_netdev(struct device *dev); -extern void unregister_netdev(struct device *dev); -extern int register_netdevice_notifier(struct notifier_block *nb); -extern int unregister_netdevice_notifier(struct notifier_block *nb); -/* Functions used for multicast support */ -extern void dev_mc_upload(struct device *dev); -extern void dev_mc_delete(struct device *dev, void *addr, int alen, int all); -extern void dev_mc_add(struct device *dev, void *addr, int alen, int newonly); -extern void dev_mc_discard(struct device *dev); -/* This is the wrong place but it'll do for the moment */ -extern void ip_mc_allhost(struct device *dev); -#endif /* __KERNEL__ */ - -#endif /* _LINUX_DEV_H */ diff --git a/pfinet/linux/notifier.h b/pfinet/linux/notifier.h deleted file mode 100644 index 78a44649..00000000 --- a/pfinet/linux/notifier.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Routines to manage notifier chains for passing status changes to any - * interested routines. We need this instead of hard coded call lists so - * that modules can poke their nose into the innards. The network devices - * needed them so here they are for the rest of you. - * - * Alan Cox - */ - -#ifndef _LINUX_NOTIFIER_H -#define _LINUX_NOTIFIER_H -#include - -struct notifier_block -{ - int (*notifier_call)(unsigned long, void *); - struct notifier_block *next; - int priority; -}; - - -#ifdef __KERNEL__ - -#define NOTIFY_DONE 0x0000 /* Don't care */ -#define NOTIFY_OK 0x0001 /* Suits me */ -#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */ - -extern __inline__ int notifier_chain_register(struct notifier_block **list, struct notifier_block *n) -{ - while(*list) - { - if(n->priority > (*list)->priority) - break; - list= &((*list)->next); - } - n->next = *list; - *list=n; - return 0; -} - -/* - * Warning to any non GPL module writers out there.. these functions are - * GPL'd - */ - -extern __inline__ int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n) -{ - while((*nl)!=NULL) - { - if((*nl)==n) - { - *nl=n->next; - return 0; - } - nl=&((*nl)->next); - } - return -ENOENT; -} - -/* - * This is one of these things that is generally shorter inline - */ - -extern __inline__ int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v) -{ - int ret=NOTIFY_DONE; - struct notifier_block *nb = *n; - while(nb) - { - ret=nb->notifier_call(val,v); - if(ret&NOTIFY_STOP_MASK) - return ret; - nb=nb->next; - } - return ret; -} - - -/* - * Declared notifiers so far. I can imagine quite a few more chains - * over time (eg laptop power reset chains, reboot chain (to clean - * device units up), device [un]mount chain, module load/unload chain, - * low memory chain, screenblank chain (for plug in modular screenblankers) - * VC switch chains (for loadable kernel svgalib VC switch helpers) etc... - */ - -/* netdevice notifier chain */ -#define NETDEV_UP 0x0001 /* For now you can't veto a device up/down */ -#define NETDEV_DOWN 0x0002 -#define NETDEV_REBOOT 0x0003 /* Tell a protocol stack a network interface - detected a hardware crash and restarted - - we can use this eg to kick tcp sessions - once done */ -#endif -#endif diff --git a/pfinet/linux/param.h b/pfinet/linux/param.h deleted file mode 100644 index 39efaf0d..00000000 --- a/pfinet/linux/param.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/pfinet/linux/route.h b/pfinet/linux/route.h deleted file mode 100644 index 3cadd206..00000000 --- a/pfinet/linux/route.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the IP router interface. - * - * Version: @(#)route.h 1.0.3 05/27/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_ROUTE_H -#define _LINUX_ROUTE_H - -#include - - -/* This structure gets passed by the SIOCADDRTOLD and SIOCDELRTOLD calls. */ - -struct old_rtentry { - unsigned long rt_genmask; - struct sockaddr rt_dst; - struct sockaddr rt_gateway; - short rt_flags; - short rt_refcnt; - unsigned long rt_use; - char *rt_dev; -}; - -/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */ -struct rtentry { - unsigned long rt_hash; /* hash key for lookups */ - struct sockaddr rt_dst; /* target address */ - struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ - struct sockaddr rt_genmask; /* target network mask (IP) */ - short rt_flags; - short rt_refcnt; - unsigned long rt_use; - struct ifnet *rt_ifp; - short rt_metric; /* +1 for binary compatibility! */ - char *rt_dev; /* forcing the device at add */ - unsigned long rt_mss; /* per route MTU/Window */ - unsigned long rt_window; /* Window clamping */ -}; - - -#define RTF_UP 0x0001 /* route usable */ -#define RTF_GATEWAY 0x0002 /* destination is a gateway */ -#define RTF_HOST 0x0004 /* host entry (net otherwise) */ -#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */ -#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ -#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ -#define RTF_MSS 0x0040 /* specific MSS for this route */ -#define RTF_WINDOW 0x0080 /* per route window clamping */ - -/* - * REMOVE THESE BY 1.2.0 !!!!!!!!!!!!!!!!! - */ - -#define RTF_MTU RTF_MSS -#define rt_mtu rt_mss - -#endif /* _LINUX_ROUTE_H */ diff --git a/pfinet/linux/sched.h b/pfinet/linux/sched.h deleted file mode 100644 index acc60944..00000000 --- a/pfinet/linux/sched.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _HACK_SCHED_H -#define _HACK_SCHED_H - -#include -#include -#include -#include -#include -#include -#include "mapped-time.h" -#include -#include -#include - -#define jiffies (fetch_jiffies ()) -extern struct task_struct *current; -extern struct task_struct current_contents; - -struct task_struct -{ - uid_t pgrp, pid; - int flags; - int timeout; - int signal; - int blocked; - int state; - int isroot; -}; - -/* FLAGS in task_struct's. */ -#define PF_EXITING 1 -/* STATE in task_struct's. */ -#define TASK_INTERRUPTIBLE 1 -#define TASK_RUNNING 2 - -extern inline int -suser () -{ - return current->isroot; -}; - -void wake_up_interruptible (struct wait_queue **); -void interruptible_sleep_on (struct wait_queue **); - -void select_wait (struct wait_queue **, select_table *); - -void schedule (void); - -#define SEL_IN SELECT_READ -#define SEL_OUT SELECT_WRITE -#define SEL_EX SELECT_URG - -/* This function is used only to send SIGPIPE to the current - task. In all such cases, EPIPE is returned anyhow. In the - Hurd, servers are not responsible for SIGPIPE; the library - does that itself upon receiving EPIPE. So we can just - NOP such calls. */ -extern inline int -send_sig (u_long signo, struct task_struct *task, int priv) -{ - assert (signo == SIGPIPE); - assert (task == current); - return 0; -} - -int fetch_current_time (void); -struct timeval fetch_xtime (void); - -#define xtime (fetch_xtime ()) -#define CURRENT_TIME (xtime.tv_sec) - -static struct timeval _xtime_buf; - -extern inline struct timeval -fetch_xtime () -{ - maptime_read (mapped_time, &_xtime_buf); - return _xtime_buf; -} - -#endif diff --git a/pfinet/linux/skbuff.h b/pfinet/linux/skbuff.h deleted file mode 100644 index 817f89d7..00000000 --- a/pfinet/linux/skbuff.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Definitions for the 'struct sk_buff' memory handlers. - * - * Authors: - * Alan Cox, - * Florian La Roche, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _LINUX_SKBUFF_H -#define _LINUX_SKBUFF_H -#include -#include -#include -#include - -#undef CONFIG_SKB_CHECK - -#define HAVE_ALLOC_SKB /* For the drivers to know */ - - -#define FREE_READ 1 -#define FREE_WRITE 0 - - -struct sk_buff_head { - struct sk_buff * volatile next; - struct sk_buff * volatile prev; -#if CONFIG_SKB_CHECK - int magic_debug_cookie; -#endif -}; - - -struct sk_buff { - struct sk_buff * volatile next; - struct sk_buff * volatile prev; -#if CONFIG_SKB_CHECK - int magic_debug_cookie; -#endif - struct sk_buff * volatile link3; - struct sock *sk; - volatile unsigned long when; /* used to compute rtt's */ - struct timeval stamp; - struct device *dev; - struct sk_buff *mem_addr; - union { - struct tcphdr *th; - struct ethhdr *eth; - struct iphdr *iph; - struct udphdr *uh; - unsigned char *raw; - unsigned long seq; - } h; - struct iphdr *ip_hdr; /* For IPPROTO_RAW */ - unsigned long mem_len; - unsigned long len; - unsigned long fraglen; - struct sk_buff *fraglist; /* Fragment list */ - unsigned long truesize; - unsigned long saddr; - unsigned long daddr; - unsigned long raddr; /* next hop addr */ - volatile char acked, - used, - free, - arp; - unsigned char tries,lock,localroute,pkt_type; -#define PACKET_HOST 0 /* To us */ -#define PACKET_BROADCAST 1 -#define PACKET_MULTICAST 2 -#define PACKET_OTHERHOST 3 /* Unmatched promiscuous */ - unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ - unsigned short pkt_class; /* For drivers that need to cache the packet type with the skbuff (new PPP) */ -#ifdef CONFIG_SLAVE_BALANCING - unsigned short in_dev_queue; -#endif - unsigned long padding[0]; - unsigned char data[0]; -}; - -#define SK_WMEM_MAX 32767 -#define SK_RMEM_MAX 32767 - -#ifdef CONFIG_SKB_CHECK -#define SK_FREED_SKB 0x0DE2C0DE -#define SK_GOOD_SKB 0xDEC0DED1 -#define SK_HEAD_SKB 0x12231298 -#endif - -#ifdef __KERNEL__ -/* - * Handling routines are only of interest to the kernel - */ - -#include - -#if 0 -extern void print_skb(struct sk_buff *); -#endif -extern void kfree_skb(struct sk_buff *skb, int rw); -extern void skb_queue_head_init(struct sk_buff_head *list); -extern void skb_queue_head(struct sk_buff_head *list,struct sk_buff *buf); -extern void skb_queue_tail(struct sk_buff_head *list,struct sk_buff *buf); -extern struct sk_buff * skb_dequeue(struct sk_buff_head *list); -extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk); -extern void skb_append(struct sk_buff *old,struct sk_buff *newsk); -extern void skb_unlink(struct sk_buff *buf); -extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list); -extern struct sk_buff * alloc_skb(unsigned int size, int priority); -extern void kfree_skbmem(struct sk_buff *skb, unsigned size); -extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority); -extern void skb_device_lock(struct sk_buff *skb); -extern void skb_device_unlock(struct sk_buff *skb); -extern void dev_kfree_skb(struct sk_buff *skb, int mode); -extern int skb_device_locked(struct sk_buff *skb); -/* - * Peek an sk_buff. Unlike most other operations you _MUST_ - * be careful with this one. A peek leaves the buffer on the - * list and someone else may run off with it. For an interrupt - * type system cli() peek the buffer copy the data and sti(); - */ -static __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_) -{ - struct sk_buff *list = (struct sk_buff *)list_; - return (list->next != list)? list->next : NULL; -} - -#if CONFIG_SKB_CHECK -extern int skb_check(struct sk_buff *skb,int,int, char *); -#define IS_SKB(skb) skb_check((skb), 0, __LINE__,__FILE__) -#define IS_SKB_HEAD(skb) skb_check((skb), 1, __LINE__,__FILE__) -#else -#define IS_SKB(skb) -#define IS_SKB_HEAD(skb) - -extern __inline__ void skb_queue_head_init(struct sk_buff_head *list) -{ - list->prev = (struct sk_buff *)list; - list->next = (struct sk_buff *)list; -} - -/* - * Insert an sk_buff at the start of a list. - */ - -extern __inline__ void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk) -{ - unsigned long flags; - struct sk_buff *list = (struct sk_buff *)list_; - - save_flags(flags); - cli(); - newsk->next = list->next; - newsk->prev = list; - newsk->next->prev = newsk; - newsk->prev->next = newsk; - restore_flags(flags); -} - -/* - * Insert an sk_buff at the end of a list. - */ - -extern __inline__ void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk) -{ - unsigned long flags; - struct sk_buff *list = (struct sk_buff *)list_; - - save_flags(flags); - cli(); - - newsk->next = list; - newsk->prev = list->prev; - - newsk->next->prev = newsk; - newsk->prev->next = newsk; - - restore_flags(flags); -} - -/* - * Remove an sk_buff from a list. This routine is also interrupt safe - * so you can grab read and free buffers as another process adds them. - */ - -extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list_) -{ - long flags; - struct sk_buff *result; - struct sk_buff *list = (struct sk_buff *)list_; - - save_flags(flags); - cli(); - - result = list->next; - if (result == list) { - restore_flags(flags); - return NULL; - } - - result->next->prev = list; - list->next = result->next; - - result->next = NULL; - result->prev = NULL; - - restore_flags(flags); - - return result; -} - -/* - * Insert a packet before another one in a list. - */ - -extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk) -{ - unsigned long flags; - - save_flags(flags); - cli(); - newsk->next = old; - newsk->prev = old->prev; - old->prev = newsk; - newsk->prev->next = newsk; - - restore_flags(flags); -} - -/* - * Place a packet after a given packet in a list. - */ - -extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - newsk->prev = old; - newsk->next = old->next; - newsk->next->prev = newsk; - old->next = newsk; - - restore_flags(flags); -} - -/* - * Remove an sk_buff from its list. Works even without knowing the list it - * is sitting on, which can be handy at times. It also means that THE LIST - * MUST EXIST when you unlink. Thus a list must have its contents unlinked - * _FIRST_. - */ - -extern __inline__ void skb_unlink(struct sk_buff *skb) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - if(skb->prev && skb->next) - { - skb->next->prev = skb->prev; - skb->prev->next = skb->next; - skb->next = NULL; - skb->prev = NULL; - } - restore_flags(flags); -} - -#endif - -extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); -extern int datagram_select(struct sock *sk, int sel_type, select_table *wait); -extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); -extern void skb_free_datagram(struct sk_buff *skb); - -#endif /* __KERNEL__ */ -#endif /* _LINUX_SKBUFF_H */ diff --git a/pfinet/linux/socket.h b/pfinet/linux/socket.h deleted file mode 100644 index 22dd05ce..00000000 --- a/pfinet/linux/socket.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _HACK_SOCKET_H_ -#define _HACK_SOCKET_H_ - -#include -#include - -#define IP_MAX_MEMBERSHIPS 10 - -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 - -#define SOPRI_INTERACTIVE 0 -#define SOPRI_NORMAL 1 -#define SOPRI_BACKGROUND 2 - -#define SOL_IP IPPROTO_IP -#define SOL_TCP IPPROTO_TCP - -/* TCP options */ -#define TCP_NODELAY 1 -#define TCP_MAXSEG 2 - -#define SO_NO_CHECK 11 -#define SO_PRIORITY 12 - -#endif diff --git a/pfinet/linux/sockios.h b/pfinet/linux/sockios.h deleted file mode 100644 index e69de29b..00000000 diff --git a/pfinet/linux/stat.h b/pfinet/linux/stat.h deleted file mode 100644 index 5165069b..00000000 --- a/pfinet/linux/stat.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/pfinet/linux/string.h b/pfinet/linux/string.h deleted file mode 100644 index 3b2f5900..00000000 --- a/pfinet/linux/string.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/pfinet/linux/tcp.h b/pfinet/linux/tcp.h deleted file mode 100644 index 32ef0ad1..00000000 --- a/pfinet/linux/tcp.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the TCP protocol. - * - * Version: @(#)tcp.h 1.0.2 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_TCP_H -#define _LINUX_TCP_H - - -#define HEADER_SIZE 64 /* maximum header size */ - - -struct tcphdr { - __u16 source; - __u16 dest; - __u32 seq; - __u32 ack_seq; -#if defined(__i386__) - __u16 res1:4, - doff:4, - fin:1, - syn:1, - rst:1, - psh:1, - ack:1, - urg:1, - res2:2; -#elif defined(__mc68000__) - __u16 res2:2, - urg:1, - ack:1, - psh:1, - rst:1, - syn:1, - fin:1, - doff:4, - res1:4; -#elif defined(__MIPSEL__) - __u16 res1:4, - doff:4, - fin:1, - syn:1, - rst:1, - psh:1, - ack:1, - urg:1, - res2:2; -#elif defined(__MIPSEB__) - __u16 res2:2, - urg:1, - ack:1, - psh:1, - rst:1, - syn:1, - fin:1, - doff:4, - res1:4; -#elif defined(__alpha__) - __u16 res1:4, - doff:4, - fin:1, - syn:1, - rst:1, - psh:1, - ack:1, - urg:1, - res2:2; -#elif defined(__sparc__) - __u16 res2:2, - urg:1, - ack:1, - psh:1, - rst:1, - syn:1, - fin:1, - doff:4, - res1:4; -#else -#error "Adjust this structure for your cpu alignment rules" -#endif - __u16 window; - __u16 check; - __u16 urg_ptr; -}; - - -enum { - TCP_ESTABLISHED = 1, - TCP_SYN_SENT, - TCP_SYN_RECV, - TCP_FIN_WAIT1, - TCP_FIN_WAIT2, - TCP_TIME_WAIT, - TCP_CLOSE, - TCP_CLOSE_WAIT, - TCP_LAST_ACK, - TCP_LISTEN, - TCP_CLOSING /* now a valid state */ -}; - -#endif /* _LINUX_TCP_H */ diff --git a/pfinet/linux/termios.h b/pfinet/linux/termios.h deleted file mode 100644 index 9e269565..00000000 --- a/pfinet/linux/termios.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/pfinet/linux/time.h b/pfinet/linux/time.h deleted file mode 100644 index 50e13783..00000000 --- a/pfinet/linux/time.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _HACK_TIME_H_ -#define _HACK_TIME_H_ - -#include -#include "mapped-time.h" - -extern inline void -do_gettimeofday (struct timeval *tp) -{ - maptime_read (mapped_time, &_xtime_buf); -} - -#endif diff --git a/pfinet/linux/timer.h b/pfinet/linux/timer.h deleted file mode 100644 index 2458746e..00000000 --- a/pfinet/linux/timer.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _HACK_TIMER_H_ -#define _HACK_TIMER_H_ - -#include - -enum tstate -{ - TIMER_INACTIVE, - TIMER_STARTING, - TIMER_STARTED, - TIMER_EXPIRED, - TIMER_FUNCTION_RUNNING, -}; - -struct timer_list -{ - struct timer_list *next, **prevp; - unsigned long expires; - unsigned long data; - void (*function)(unsigned long); -}; - -void add_timer (struct timer_list *); -int del_timer (struct timer_list *); -void init_timer (struct timer_list *); - -#endif diff --git a/pfinet/linux/types.h b/pfinet/linux/types.h deleted file mode 100644 index c978fb07..00000000 --- a/pfinet/linux/types.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _HACK_TYPES_H -#define _HACK_TYPES_H - -#include -typedef unsigned char __u8; -typedef unsigned short __u16; -typedef unsigned long __u32; - -/* Hackery */ -struct inode -{ - uid_t i_uid; -}; - - -#endif diff --git a/pfinet/linux/udp.h b/pfinet/linux/udp.h deleted file mode 100644 index 471301a2..00000000 --- a/pfinet/linux/udp.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the UDP protocol. - * - * Version: @(#)udp.h 1.0.2 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_UDP_H -#define _LINUX_UDP_H - - -struct udphdr { - unsigned short source; - unsigned short dest; - unsigned short len; - unsigned short check; -}; - - -#endif /* _LINUX_UDP_H */ diff --git a/pfinet/linux/un.h b/pfinet/linux/un.h deleted file mode 100644 index e69de29b..00000000 diff --git a/pfinet/linux/wait.h b/pfinet/linux/wait.h deleted file mode 100644 index 15759ad2..00000000 --- a/pfinet/linux/wait.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _HACK_WAIT_H_ -#define _HACK_WAIT_H_ - -#include - -struct wait_queue -{ - struct condition c; -}; - -struct select_table_elt -{ - struct condition *dependent_condition; - struct select_table_elt *next; -}; - -typedef struct select_table_struct -{ - struct condition master_condition; - struct select_table_elt *head; -} select_table; - -#endif diff --git a/pfinet/loopback.c b/pfinet/loopback.c index 0d3681fb..068cf3c8 100644 --- a/pfinet/loopback.c +++ b/pfinet/loopback.c @@ -1,6 +1,5 @@ /* Loopback "device" for pfinet - Copyright (C) 1996, 1998 Free Software Foundation, Inc. - Written by Thomas Bushnell, n/BSG. + Copyright (C) 1996,98,2000 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -18,79 +17,114 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ -#include +#include "pfinet.h" #include #include -#include "pfinet.h" - -struct device loopback_dev; - -int -loopback_xmit (struct sk_buff *skb, struct device *dev) +#include +#include +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include /* For ARPHRD_ETHER */ + +#define LOOPBACK_MTU (vm_page_size - 172) + +/* + * The higher levels take care of making this non-reentrant (it's + * called with bh's disabled). + */ +static int loopback_xmit(struct sk_buff *skb, struct device *dev) { - int done; - - if (!skb || !dev) - return 0; - - if (dev->tbusy) - return 1; - - dev->tbusy; - - done = dev_rint (skb->data, skb->len, 0, dev); - dev_kfree_skb (skb, FREE_WRITE); - - while (done != 1) - done = dev_rint (0, 0, 0, dev); - - dev->tbusy = 0; - return 0; + struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + + /* + * Take this out if the debug says its ok + */ + + if (skb == NULL || dev == NULL) + printk(KERN_DEBUG "loopback fed NULL data - splat\n"); + + /* + * Optimise so buffers with skb->free=1 are not copied but + * instead are lobbed from tx queue to rx queue + */ + + if(atomic_read(&skb->users) != 1) + { + struct sk_buff *skb2=skb; + skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */ + if(skb==NULL) { + kfree_skb(skb2); + return 0; + } + kfree_skb(skb2); + } + else + skb_orphan(skb); + + skb->protocol=eth_type_trans(skb,dev); + skb->dev=dev; +#ifndef LOOPBACK_MUST_CHECKSUM + skb->ip_summed = CHECKSUM_UNNECESSARY; +#endif + netif_rx(skb); + + stats->rx_bytes+=skb->len; + stats->tx_bytes+=skb->len; + stats->rx_packets++; + stats->tx_packets++; + + return(0); } -u_int16_t -loopback_type_trans (struct sk_buff *skb, struct device *dev) +static struct net_device_stats *get_stats(struct device *dev) { - return htons (ETH_P_IP); + return (struct net_device_stats *)dev->priv; } +static int loopback_open(struct device *dev) +{ + dev->flags|=IFF_LOOPBACK; + return 0; +} -void -setup_loopback_device (char *name) +/* Initialize the rest of the LOOPBACK device. */ +static int loopback_init(struct device *dev) { - int i; - - loopback_dev.name = name; - for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init (&loopback_dev.buffs[i]); - - loopback_dev.open = 0; - loopback_dev.stop = 0; - loopback_dev.hard_start_xmit = loopback_xmit; - loopback_dev.hard_header = 0; - loopback_dev.rebuild_header = 0; - loopback_dev.type_trans = loopback_type_trans; - loopback_dev.get_stats = 0; - loopback_dev.set_multicast_list = 0; - - loopback_dev.type = 0; - loopback_dev.addr_len = 0; - loopback_dev.flags = IFF_LOOPBACK | IFF_BROADCAST | IFF_UP; - loopback_dev.family = AF_INET; - - loopback_dev.mtu = 2000; - - /* Defaults */ - loopback_dev.pa_addr = inet_addr ("127.0.0.1"); - loopback_dev.pa_brdaddr = inet_addr ("127.255.255.255"); - loopback_dev.pa_mask = inet_addr ("255.0.0.0"); - loopback_dev.pa_alen = sizeof (unsigned long); - - loopback_dev.next = dev_base; - dev_base = &loopback_dev; - - /* Add the route */ - ip_rt_add (RTF_HOST, loopback_dev.pa_addr, 0xffffffff, 0, &loopback_dev, - loopback_dev.mtu, 0); + dev->mtu = LOOPBACK_MTU; + dev->tbusy = 0; + dev->hard_start_xmit = loopback_xmit; + dev->hard_header = eth_header; + dev->hard_header_cache = eth_header_cache; + dev->header_cache_update= eth_header_cache_update; + dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->addr_len = ETH_ALEN; /* 6 */ + dev->tx_queue_len = 0; + dev->type = ARPHRD_LOOPBACK; /* 0x0001 */ + dev->rebuild_header = eth_rebuild_header; + dev->open = loopback_open; + dev->flags = IFF_LOOPBACK; + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_device_stats)); + dev->get_stats = get_stats; + + /* + * Fill in the generic fields of the device structure. + */ + + dev_init_buffers(dev); + + return(0); } + + +struct device loopback_dev = { name: "lo", init: &loopback_init, }; + +/* It is important magic that this is the first thing on the list. */ +struct device *dev_base = &loopback_dev; diff --git a/pfinet/main.c b/pfinet/main.c index 0232dd66..bd0c44f3 100644 --- a/pfinet/main.c +++ b/pfinet/main.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + Copyright (C) 1995,96,97,99,2000 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -27,6 +27,9 @@ #include #include +#include +#include + int trivfs_fstype = FSTYPE_MISC; int trivfs_fsid; int trivfs_support_read = 0; @@ -141,12 +144,6 @@ find_device (char *name, struct device **device) setup_ethernet_device (name); - /* Default mask is 255.255.255.0. XXX should be class dependent. */ - { - char addr[4] = {255, 255, 255, 0}; - ether_dev.pa_mask = *(u_long *)addr; - } - /* Turn on device. */ dev_open (ðer_dev); @@ -168,6 +165,9 @@ enumerate_devices (error_t (*fun) (struct device *dev)) return 0; } +extern void sk_init (void), skb_init (void); +extern int net_dev_init (void); + int main (int argc, char **argv) @@ -186,19 +186,37 @@ main (int argc, /* Generic initialization */ - init_devices (); init_time (); - cthread_detach (cthread_fork (input_work_thread, 0)); - inet_proto_init (0); + ethernet_initialize (); + cthread_detach (cthread_fork (net_bh_worker, 0)); - arrange_shutdown_notification (); + __mutex_lock (&global_lock); - setup_loopback_device ("loopback"); + prepare_current (1); /* Set up to call into Linux initialization. */ - /* Parse options. */ + sk_init (); +#ifdef SLAB_SKB + skb_init (); +#endif + inet_proto_init (0); + + /* This initializes the Linux network device layer, including + initializing each device on the `dev_base' list. For us, + that means just loopback_dev, which will get fully initialized now. + After this, we can use `register_netdevice' for new interfaces. */ + net_dev_init (); + + /* Parse options. When successful, this configures the interfaces + before returning. (And when not sucessful, it never returns.) */ argp_parse (&pfinet_argp, argc, argv, 0,0,0); - /* Talk to parent and link us in. */ + __mutex_unlock (&global_lock); + + /* Ask init to tell us when the system is going down, + so we can try to be friendly to our correspondents on the network. */ + arrange_shutdown_notification (); + + /* Talk to parent and link us in. */ task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) error (1, 0, "Must be started as a translator"); @@ -207,7 +225,7 @@ main (int argc, trivfs_cntl_portclasses[0], pfinet_bucket, trivfs_protid_portclasses[0], pfinet_bucket, 0); if (err) - error (1, errno, "contacting parent"); + error (1, err, "contacting parent"); /* Launch */ ports_manage_port_operations_multithread (pfinet_bucket, diff --git a/pfinet/misc.c b/pfinet/misc.c index 6eb96b89..56611daf 100644 --- a/pfinet/misc.c +++ b/pfinet/misc.c @@ -1,5 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* + Copyright (C) 1995,96,2000 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -20,56 +20,45 @@ #include "pfinet.h" #include +#include + +#include +#include -/* Create a sock_user structure, initialized from SOCK and ISROOT. - If NOINSTALL is set, don't put it in the portset. */ -struct sock_user * -make_sock_user (struct socket *sock, int isroot, int noinstall) -{ - struct sock_user *user; - - if (noinstall) - errno = ports_create_port_noinstall (socketport_class, pfinet_bucket, - sizeof (struct sock_user), &user); - else - errno = ports_create_port (socketport_class, pfinet_bucket, - sizeof (struct sock_user), &user); - if (errno) - return 0; - - user->isroot = isroot; - user->sock = sock; - sock->refcnt++; - return user; -} /* Create a sockaddr port. Fill in *ADDR and *ADDRTYPE accordingly. - The address should come from SOCK; PEER is 0 if we want this socket's + The address should come from SOCK; PEER is 0 if we want this socket's name and 1 if we want the peer's name. */ error_t -make_sockaddr_port (struct socket *sock, +make_sockaddr_port (struct socket *sock, int peer, mach_port_t *addr, mach_msg_type_name_t *addrtype) { - char buf[128]; - int buflen = 128; + union { struct sockaddr_storage storage; struct sockaddr sa; } buf; + int buflen = sizeof buf; error_t err; struct sock_addr *addrstruct; - err = (*sock->ops->getname) (sock, (struct sockaddr *)buf, &buflen, peer); + err = (*sock->ops->getname) (sock, &buf.sa, &buflen, peer); if (err) return err; - + err = ports_create_port (addrport_class, pfinet_bucket, - sizeof (struct sock_addr) + buflen, &addrstruct); - if (err) - return err; - addrstruct->len = buflen; - bcopy (buf, addrstruct->address, buflen); - *addr = ports_get_right (addrstruct); - *addrtype = MACH_MSG_TYPE_MAKE_SEND; + (offsetof (struct sock_addr, address) + + buflen), &addrstruct); + if (!err) + { + addrstruct->address.sa_family = buf.sa.sa_family; + addrstruct->address.sa_len = buflen; + memcpy (addrstruct->address.sa_data, buf.sa.sa_data, + buflen - offsetof (struct sockaddr, sa_data)); + *addr = ports_get_right (addrstruct); + *addrtype = MACH_MSG_TYPE_MAKE_SEND; + } + ports_port_deref (addrstruct); + return 0; } @@ -104,86 +93,3 @@ void clean_addrport (void *arg) { } - -/* Release the reference on the referenced socket. */ -void -clean_socketport (void *arg) -{ - struct sock_user *user = arg; - - mutex_lock (&global_lock); - - user->sock->refcnt--; - if (user->sock->refcnt == 0) - sock_release (user->sock); - - mutex_unlock (&global_lock); -} - -struct socket * -sock_alloc (void) -{ - struct socket *sock; - struct wait_queue *wait, **waitp; - - sock = malloc (sizeof (struct wait_queue) - + sizeof (struct wait_queue *) - + sizeof (struct socket)); - wait = (void *)sock + sizeof (struct socket); - waitp = (void *)wait + sizeof (struct wait_queue); - - bzero (sock, sizeof (struct socket)); - sock->identity = MACH_PORT_NULL; - sock->state = SS_UNCONNECTED; - sock->wait = waitp; - - condition_init (&wait->c); - - *waitp = wait; - - return sock; -} - -static inline void sock_release_peer(struct socket *peer) -{ - peer->state = SS_DISCONNECTING; - wake_up_interruptible(peer->wait); - sock_wake_async(peer, 1); -} - -void -sock_release (struct socket *sock) -{ - int oldstate; - struct socket *peersock, *nextsock; - - if ((oldstate = sock->state) != SS_UNCONNECTED) - sock->state = SS_DISCONNECTING; - - /* - * Wake up anyone waiting for connections. - */ - - for (peersock = sock->iconn; peersock; peersock = nextsock) - { - nextsock = peersock->next; - sock_release_peer(peersock); - } - - /* - * Wake up anyone we're connected to. First, we release the - * protocol, to give it a chance to flush data, etc. - */ - - peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL; - if (sock->ops) - (*sock->ops->release) (sock, peersock); - if (peersock) - sock_release_peer(peersock); - - if (sock->identity != MACH_PORT_NULL) - mach_port_destroy (mach_task_self (), sock->identity); - free (sock); -} - - diff --git a/pfinet/mutations.h b/pfinet/mutations.h index 8c0df887..f63ad9b9 100644 --- a/pfinet/mutations.h +++ b/pfinet/mutations.h @@ -1,4 +1,4 @@ -/* +/* Copyright (C) 1995 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. diff --git a/pfinet/options.c b/pfinet/options.c index b308dc36..c565db18 100644 --- a/pfinet/options.c +++ b/pfinet/options.c @@ -1,8 +1,8 @@ /* Pfinet option parsing - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996,97,2000 Free Software Foundation, Inc. - Written by Miles Bader + Written by Miles Bader This file is part of the GNU Hurd. @@ -25,11 +25,15 @@ #include #include #include +#include #include #include #include "pfinet.h" +#include +#include + /* Our interface to the set of devices. */ extern error_t find_device (char *name, struct device **device); extern error_t enumerate_devices (error_t (*fun) (struct device *dev)); @@ -117,6 +121,7 @@ parse_opt (int opt, char *arg, struct argp_state *state) /* Parse STR and return the corresponding internet address. If STR is not a valid internet address, signal an error mentioned TYPE. */ +#undef ADDR #define ADDR(str, type) \ ({ unsigned long addr = inet_addr (str); \ if (addr == INADDR_NONE) PERR (EINVAL, "Malformed %s", type); \ @@ -154,16 +159,16 @@ parse_opt (int opt, char *arg, struct argp_state *state) break; case 'a': - h->curint->address = ADDR (arg, "address"); + h->curint->address = ADDR (arg, "address"); if (!IN_CLASSA (ntohl (h->curint->address)) && !IN_CLASSB (ntohl (h->curint->address)) && !IN_CLASSC (ntohl (h->curint->address))) { if (IN_MULTICAST (ntohl (h->curint->address))) - FAIL (EINVAL, 1, 0, - "%s: Cannot set interface address to multicast address", + FAIL (EINVAL, 1, 0, + "%s: Cannot set interface address to multicast address", arg); - else + else FAIL (EINVAL, 1, 0, "%s: Illegal or undefined network address", arg); } @@ -202,52 +207,26 @@ parse_opt (int opt, char *arg, struct argp_state *state) FAIL (err, 13, 0, "No default interface"); } +#if 0 /* XXX what does this mean??? */ /* Check for bogus option combinations. */ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) if (in->netmask != INADDR_NONE && in->address == INADDR_NONE && in->device->pa_addr == 0) /* Specifying a netmask for an address-less interface is a no-no. */ FAIL (EDESTADDRREQ, 14, 0, "Cannot set netmask"); +#endif /* Successfully finished parsing, return a result. */ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) - { - struct device *dev = in->device; - if (in->address != INADDR_NONE || in->netmask != INADDR_NONE) - { - if (dev->pa_addr != 0) - /* There's already an address, delete the old entry. */ - ip_rt_del (dev->pa_addr & dev->pa_mask, dev); - - if (in->address != INADDR_NONE) - dev->pa_addr = in->address; - - if (in->netmask != INADDR_NONE) - dev->pa_mask = in->netmask; - else - { - if (IN_CLASSA (ntohl (dev->pa_addr))) - dev->pa_mask = htonl (IN_CLASSA_NET); - else if (IN_CLASSB (ntohl (dev->pa_addr))) - dev->pa_mask = htonl (IN_CLASSB_NET); - else if (IN_CLASSC (ntohl (dev->pa_addr))) - dev->pa_mask = htonl (IN_CLASSC_NET); - else - abort (); - } - - dev->family = AF_INET; - dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; - - ip_rt_add (0, dev->pa_addr & dev->pa_mask, dev->pa_mask, - 0, dev, 0, 0); - } - if (in->gateway != INADDR_NONE) - { - ip_rt_del (0, dev); - ip_rt_add (RTF_GATEWAY, 0, 0, in->gateway, dev, 0, 0); - } - } + if (in->address != INADDR_NONE || in->netmask != INADDR_NONE) + { + extern error_t configure_device (struct device *dev, + uint32_t addr, + uint32_t netmask); /* devinet.c */ + err = configure_device (in->device, in->address, in->netmask); + if (err) + error (2, err, "cannot configure interface"); /* XXX */ + } /* Fall through to free hook. */ case ARGP_KEY_ERROR: @@ -287,10 +266,12 @@ trivfs_append_args (struct trivfs_control *fsys, char **argz, size_t *argz_len) ADD_OPT ("--%s=%s", name, inet_ntoa (i)); } while (0) ADD_OPT ("--interface=%s", dev->name); +#if 0 /* XXX */ if (dev->pa_addr != 0) ADD_ADDR_OPT ("address", dev->pa_addr); if (dev->pa_mask != 0) ADD_ADDR_OPT ("netmask", dev->pa_mask); +#endif /* XXX how do we figure out the default gateway? */ #undef ADD_OPT diff --git a/pfinet/pfinet.h b/pfinet/pfinet.h index 36756615..b5c551d8 100644 --- a/pfinet/pfinet.h +++ b/pfinet/pfinet.h @@ -1,5 +1,5 @@ /* - Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1999, 2000 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -23,16 +23,12 @@ #include #include -#include #include #include +#include -extern device_t master_device; - -extern struct proto_ops *proto_ops; - -struct mutex global_lock; -struct mutex packet_queue_lock; +extern struct mutex global_lock; +extern struct mutex net_bh_lock; struct port_bucket *pfinet_bucket; struct port_class *addrport_class; @@ -55,27 +51,23 @@ struct sock_user struct sock_addr { struct port_info pi; - size_t len; - struct sockaddr address[0]; + struct sockaddr address; }; -void setup_loopback_device (char *); - +void ethernet_initialize (void); int ethernet_demuxer (mach_msg_header_t *, mach_msg_header_t *); void setup_ethernet_device (char *); -void become_task_protid (struct trivfs_protid *); -void become_task (struct sock_user *); struct sock_user *make_sock_user (struct socket *, int, int); error_t make_sockaddr_port (struct socket *, int, mach_port_t *, mach_msg_type_name_t *); void init_devices (void); -any_t input_work_thread (any_t); +any_t net_bh_worker (any_t); void init_time (void); -void inet_proto_init (struct net_proto *); void ip_rt_add (short, u_long, u_long, u_long, struct device *, u_short, u_long); void ip_rt_del (u_long, struct device *); -int tcp_readable (struct sock *); +struct sock; +error_t tcp_tiocinq (struct sock *sk, mach_msg_type_number_t *amount); struct sock_user *begin_using_socket_port (socket_t); diff --git a/pfinet/sched.c b/pfinet/sched.c index 41059b3f..53f0cb09 100644 --- a/pfinet/sched.c +++ b/pfinet/sched.c @@ -1,6 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - Written by Michael I. Bushnell, p/BSG. +/* + Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -18,38 +17,21 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ +#include "pfinet.h" + #include #include -#include "pfinet.h" +#include struct mutex global_lock = MUTEX_INITIALIZER; -struct mutex packet_queue_lock = MUTEX_INITIALIZER; - -struct task_struct current_contents; -struct task_struct *current = ¤t_contents; - -void -interruptible_sleep_on (struct wait_queue **p) -{ - int cancel; - - cancel = hurd_condition_wait (&(*p)->c, &global_lock); - if (cancel) - current->signal = 1; -} +struct mutex net_bh_lock = MUTEX_INITIALIZER; +struct condition net_bh_wakeup = CONDITION_INITIALIZER; -void -wake_up_interruptible (struct wait_queue **p) -{ - /* tcp.c uses an unitialized wait queue; don't bomb - if we see it. */ - if (*p) - condition_broadcast (&(*p)->c); -} +struct task_struct current_contents; /* zeros are right default values */ /* Wake up the owner of the SOCK. If HOW is zero, then just - send SIGIO. If HOW is one, then send SIGIO only if the + send SIGIO. If HOW is one, then send SIGIO only if the SO_WAITDATA flag is off. If HOW is two, then send SIGIO only if the SO_NOSPACE flag is on, and also clear it. */ int @@ -60,28 +42,28 @@ sock_wake_async (struct socket *sock, int how) } -/* Set the contents of current appropriately for an RPC being undertaken - by USER. */ -void -become_task (struct sock_user *user) -{ - /* These fields are not really used currently. */ - current->pgrp = current->pid = 0; - - current->flags = 0; - current->timeout = 0; - current->signal = current->blocked = 0; - current->state = TASK_RUNNING; - current->isroot = user->isroot; -} - -void -become_task_protid (struct trivfs_protid *protid) +/* This function is the "net_bh worker thread". + The packet receiver thread calls net/core/dev.c::netif_rx with a packet; + netif_rx either drops the packet, or enqueues it and wakes us up + via mark_bh which is really condition_broadcast on net_bh_wakeup. + The packet receiver thread holds net_bh_lock while calling netif_rx. + We wake up and take global_lock, which locks out RPC service threads. + We then also take net_bh_lock running net_bh. + Thus, only this thread running net_bh locks out the packet receiver + thread (which takes only net_bh_lock while calling netif_rx), so packets + are quickly moved from the Mach port's message queue to the `backlog' + queue, or dropped, without synchronizing with RPC service threads. + (The RPC service threads lock out the running of net_bh, but not + the queuing/dropping of packets in netif_rx.) */ +any_t +net_bh_worker (any_t arg) { - current->pgrp = current->pid = 0; - current->flags = 0; - current->timeout = 0; - current->signal = current->blocked = 0; - current->state = TASK_RUNNING; - current->isroot = protid->isroot; + __mutex_lock (&global_lock); + while (1) + { + condition_wait (&net_bh_wakeup, &global_lock); + __mutex_lock (&net_bh_lock); + net_bh (); + __mutex_unlock (&net_bh_lock); + } } diff --git a/pfinet/socket-ops.c b/pfinet/socket-ops.c index 3db4985f..bcfa7f45 100644 --- a/pfinet/socket-ops.c +++ b/pfinet/socket-ops.c @@ -1,5 +1,5 @@ /* Interface functions for the socket.defs interface. - Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + Copyright (C) 1995,96,97,99,2000 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -20,11 +20,18 @@ #include #include +#include +#include #include "pfinet.h" #include "socket_S.h" - +#include +#include +#include +#include + + error_t S_socket_create (struct trivfs_protid *master, int sock_type, @@ -48,16 +55,15 @@ S_socket_create (struct trivfs_protid *master, || protocol < 0) return EINVAL; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task_protid (master); sock = sock_alloc (); sock->type = sock_type; - sock->ops = proto_ops; - err = - (*sock->ops->create) (sock, protocol); + err = - (*net_families[PF_INET]->create) (sock, protocol); if (err) sock_release (sock); else @@ -68,7 +74,7 @@ S_socket_create (struct trivfs_protid *master, ports_port_deref (user); } - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return err; } @@ -78,26 +84,17 @@ S_socket_create (struct trivfs_protid *master, error_t S_socket_listen (struct sock_user *user, int queue_limit) { + error_t err; + if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); - + __mutex_lock (&global_lock); become_task (user); + err = - (*user->sock->ops->listen) (user->sock, queue_limit); + __mutex_unlock (&global_lock); - if (user->sock->state == SS_UNCONNECTED) - { - if (user->sock->ops && user->sock->ops->listen) - (*user->sock->ops->listen) (user->sock, queue_limit); - user->sock->flags |= SO_ACCEPTCON; - mutex_unlock (&global_lock); - return 0; - } - else - { - mutex_unlock (&global_lock); - return EINVAL; - } + return err; } error_t @@ -114,47 +111,43 @@ S_socket_accept (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); - - become_task (user); - sock = user->sock; - newsock = 0; - err = 0; - if ((sock->state != SS_UNCONNECTED) - || (!(sock->flags & SO_ACCEPTCON))) - err = EINVAL; - else if (!(newsock = sock_alloc ())) - err = ENOMEM; - - if (err) - goto out; + __mutex_lock (&global_lock); - newsock->type = sock->type; - newsock->ops = sock->ops; - - err = - (*sock->ops->dup) (newsock, sock); - if (err) - goto out; - - err = - (*sock->ops->accept) (sock, newsock, sock->userflags); - if (err) - goto out; + become_task (user); - err = make_sockaddr_port (newsock, 1, addr_port, addr_port_type); - if (err) - goto out; + newsock = sock_alloc (); + if (!newsock) + err = ENOMEM; + else + { + newsock->type = sock->type; + + err = - (*sock->ops->dup) (newsock, sock); + if (!err) + err = - (*sock->ops->accept) (sock, newsock, sock->flags); + + if (!err) + /* In Linux there is a race here with the socket closing before the + ops->getname call we do in make_sockaddr_port. Since we still + have the world locked, this shouldn't be an issue for us. */ + err = make_sockaddr_port (newsock, 1, addr_port, addr_port_type); + + if (!err) + { + newuser = make_sock_user (newsock, user->isroot, 0); + *new_port = ports_get_right (newuser); + *new_port_type = MACH_MSG_TYPE_MAKE_SEND; + ports_port_deref (newuser); + } + + if (err) + sock_release (newsock); + } - newuser = make_sock_user (newsock, user->isroot, 0); - *new_port = ports_get_right (newuser); - *new_port_type = MACH_MSG_TYPE_MAKE_SEND; - ports_port_deref (newuser); + __mutex_unlock (&global_lock); - out: - if (err && newsock) - sock_release (newsock); - mutex_unlock (&global_lock); return err; } @@ -170,25 +163,14 @@ S_socket_connect (struct sock_user *user, sock = user->sock; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); - err = 0; - - if (sock->state == SS_CONNECTED - && sock->type != SOCK_DGRAM) - err = EISCONN; - else if (sock->state != SS_UNCONNECTED - && sock->state != SS_CONNECTING - && sock->state != SS_CONNECTED) - err = EINVAL; - - if (!err) - err = - (*sock->ops->connect) (sock, addr->address, addr->len, - sock->userflags); + err = - (*sock->ops->connect) (sock, &addr->address, addr->address.sa_len, + sock->flags); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); /* MiG should do this for us, but it doesn't. */ if (!err) @@ -208,10 +190,11 @@ S_socket_bind (struct sock_user *user, if (! addr) return EADDRNOTAVAIL; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); - err = - (*user->sock->ops->bind) (user->sock, addr->address, addr->len); - mutex_unlock (&global_lock); + err = - (*user->sock->ops->bind) (user->sock, + &addr->address, addr->address.sa_len); + __mutex_unlock (&global_lock); /* MiG should do this for us, but it doesn't. */ if (!err) @@ -228,10 +211,10 @@ S_socket_name (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); make_sockaddr_port (user->sock, 0, addr_port, addr_port_name); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return 0; } @@ -245,10 +228,10 @@ S_socket_peername (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); err = make_sockaddr_port (user->sock, 1, addr_port, addr_port_name); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return err; } @@ -262,7 +245,7 @@ S_socket_connect2 (struct sock_user *user1, if (!user1 || !user2) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user1); @@ -274,15 +257,7 @@ S_socket_connect2 (struct sock_user *user1, else err = - (*user1->sock->ops->socketpair) (user1->sock, user2->sock); - if (!err) - { - user1->sock->conn = user2->sock; - user2->sock->conn = user1->sock; - user1->sock->state = SS_CONNECTED; - user2->sock->state = SS_CONNECTED; - } - - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); /* MiG should do this for us, but it doesn't. */ if (!err) @@ -299,23 +274,30 @@ S_socket_create_address (mach_port_t server, mach_port_t *addr_port, mach_msg_type_name_t *addr_port_type) { - struct sock_addr *addr; error_t err; + struct sock_addr *addrstruct; + const struct sockaddr *const sa = (void *) data; if (sockaddr_type != AF_INET) return EAFNOSUPPORT; + if (sa->sa_family != sockaddr_type + || data_len < offsetof (struct sockaddr, sa_data)) + return EINVAL; err = ports_create_port (addrport_class, pfinet_bucket, - sizeof (struct sock_addr) + data_len, &addr); + (offsetof (struct sock_addr, address) + + data_len), &addrstruct); if (err) return err; - addr->len = data_len; - bcopy (data, addr->address, data_len); + memcpy (&addrstruct->address, data, data_len); + + /* BSD does not require incoming sa_len to be set, so we don't either. */ + addrstruct->address.sa_len = data_len; - *addr_port = ports_get_right (addr); + *addr_port = ports_get_right (addrstruct); *addr_port_type = MACH_MSG_TYPE_MAKE_SEND; - ports_port_deref (addr); + ports_port_deref (addrstruct); return 0; } @@ -337,11 +319,12 @@ S_socket_whatis_address (struct sock_addr *addr, if (!addr) return EOPNOTSUPP; - *type = AF_INET; - if (*datalen < addr->len) - *data = mmap (0, addr->len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); - bcopy (addr->address, *data, addr->len); - *datalen = addr->len; + *type = addr->address.sa_family; + if (*datalen < addr->address.sa_len) + *data = mmap (0, addr->address.sa_len, + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + *datalen = addr->address.sa_len; + memcpy (*data, &addr->address, addr->address.sa_len); return 0; } @@ -355,10 +338,10 @@ S_socket_shutdown (struct sock_user *user, if (!user) return EOPNOTSUPP; - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); err = - (*user->sock->ops->shutdown) (user->sock, direction); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return err; } @@ -375,18 +358,17 @@ S_socket_getopt (struct sock_user *user, if (! user) return EOPNOTSUPP; - /* XXX all options supported in the linux code are in fact ints. */ - *datalen = sizeof (int); - - mutex_lock (&global_lock); + __mutex_lock (&global_lock); become_task (user); - err = - - (user->sock->ops->getsockopt)(user->sock, level, option, *data, datalen); + err = - (level == SOL_SOCKET ? sock_getsockopt + : *user->sock->ops->getsockopt) + (user->sock, level, option, *data, datalen); - assert (*datalen == sizeof (int)); + __mutex_unlock (&global_lock); - mutex_unlock (&global_lock); + /* XXX option data not properly typed, needs byte-swapping for netmsgserver. + Most options are ints, some like IP_OPTIONS are bytesex-neutral. */ return err; } @@ -403,13 +385,17 @@ S_socket_setopt (struct sock_user *user, if (! user) return EOPNOTSUPP; - mutex_lock (&global_lock); + /* XXX option data not properly typed, needs byte-swapping for netmsgserver. + Most options are ints, some like IP_OPTIONS are bytesex-neutral. */ + + __mutex_lock (&global_lock); become_task (user); - err = - - (user->sock->ops->setsockopt)(user->sock, level, option, data, datalen); + err = - (level == SOL_SOCKET ? sock_setsockopt + : *user->sock->ops->setsockopt) + (user->sock, level, option, data, datalen); - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); return err; } @@ -427,6 +413,11 @@ S_socket_send (struct sock_user *user, mach_msg_type_number_t *amount) { int sent; + struct iovec iov = { data, datalen }; + struct msghdr m = { msg_name: addr ? &addr->address : 0, + msg_namelen: addr ? addr->address.sa_len : 0, + msg_flags: flags, + msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 }; if (!user) return EOPNOTSUPP; @@ -435,19 +426,12 @@ S_socket_send (struct sock_user *user, if (nports != 0 || controllen != 0) return EINVAL; - mutex_lock (&global_lock); - + __mutex_lock (&global_lock); become_task (user); - - if (addr) - sent = (*user->sock->ops->sendto) (user->sock, data, datalen, - user->sock->userflags, flags, - addr->address, addr->len); - else - sent = (*user->sock->ops->send) (user->sock, data, datalen, - user->sock->userflags, flags); - - mutex_unlock (&global_lock); + if (user->sock->flags & O_NONBLOCK) + m.msg_flags |= MSG_DONTWAIT; + sent = (*user->sock->ops->sendmsg) (user->sock, &m, datalen, 0); + __mutex_unlock (&global_lock); /* MiG should do this for us, but it doesn't. */ if (addr && sent >= 0) @@ -477,50 +461,53 @@ S_socket_recv (struct sock_user *user, int *outflags, mach_msg_type_number_t amount) { - int recvd; - char addr[128]; - size_t addrlen = sizeof addr; - int didalloc = 0; + error_t err; + union { struct sockaddr_storage storage; struct sockaddr sa; } addr; + int alloced = 0; + struct iovec iov; + struct msghdr m = { msg_name: &addr.sa, msg_namelen: sizeof addr, + msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 }; if (!user) return EOPNOTSUPP; - /* For unused recvmsg interface */ - *nports = 0; - *portstype = MACH_MSG_TYPE_COPY_SEND; - *controllen = 0; - *outflags = 0; - - /* Instead of this, we should peek at the socket and only allocate - as much as necessary. */ - if (*datalen < amount) + /* Instead of this, we should peek and the socket and only + allocate as much as necessary. */ + if (amount > *datalen) { - vm_allocate (mach_task_self (), (vm_address_t *) data, amount, 1); - didalloc = 1; + *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + alloced = 1; } - mutex_lock (&global_lock); - become_task (user); - - recvd = (*user->sock->ops->recvfrom) (user->sock, *data, amount, - user->sock->userflags, flags, - (struct sockaddr *)addr, &addrlen); - - mutex_unlock (&global_lock); - - if (recvd < 0) - return (error_t)-recvd; - - *datalen = recvd; - - if (didalloc && round_page (*datalen) < round_page (amount)) - vm_deallocate (mach_task_self (), - (vm_address_t) (*data + round_page (*datalen)), - round_page (amount) - round_page (*datalen)); + iov.iov_base = *data; + iov.iov_len = amount; + __mutex_lock (&global_lock); + become_task (user); + if (user->sock->flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + err = (*user->sock->ops->recvmsg) (user->sock, &m, amount, flags, 0); + __mutex_unlock (&global_lock); - S_socket_create_address (0, AF_INET, addr, addrlen, addrport, - addrporttype); + if (err < 0) + err = -err; + else + { + *datalen = err; + if (alloced && round_page (*datalen) < round_page (amount)) + munmap (*data + round_page (*datalen), + round_page (amount) - round_page (*datalen)); + err = S_socket_create_address (0, addr.sa.sa_family, + (void *) &addr.sa, m.msg_namelen, + addrport, addrporttype); + if (err && alloced) + munmap (*data, *datalen); + + *outflags = m.msg_flags; + *nports = 0; + *portstype = MACH_MSG_TYPE_COPY_SEND; + *controllen = 0; + } - return 0; + return err; } diff --git a/pfinet/socket.c b/pfinet/socket.c index 7cbc0e9f..52bd37ff 100644 --- a/pfinet/socket.c +++ b/pfinet/socket.c @@ -1,6 +1,5 @@ -/* - Copyright (C) 1995 Free Software Foundation, Inc. - Written by Michael I. Bushnell, p/BSG. +/* + Copyright (C) 1995,2000 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -18,18 +17,103 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ -#include #include #include "pfinet.h" -struct proto_ops *proto_ops; +#include +#include + +#ifndef NPROTO +#define NPROTO (PF_INET + 1) +#endif +struct net_proto_family *net_families[NPROTO]; /* Notice that a protocol family is live; this only works for inet here. */ int -sock_register (int family, struct proto_ops *ops) +sock_register (struct net_proto_family *fam) { - assert (family == PF_INET); - proto_ops = ops; + assert (fam->family < NPROTO); + net_families[fam->family] = fam; return 0; } + +struct socket * +sock_alloc (void) +{ + struct socket *sock; + struct condition *c; + + sock = malloc (sizeof *sock + sizeof (struct condition)); + if (!sock) + return 0; + c = (void *) &sock[1]; + condition_init (c); + bzero (sock, sizeof *sock); + sock->state = SS_UNCONNECTED; + sock->identity = MACH_PORT_NULL; + sock->refcnt = 1; + sock->wait = (void *) c; + + return sock; +} + +/* Create a sock_user structure, initialized from SOCK and ISROOT. + If NOINSTALL is set, don't put it in the portset. */ +struct sock_user * +make_sock_user (struct socket *sock, int isroot, int noinstall) +{ + error_t err; + struct sock_user *user; + + assert (sock->refcnt != 0); + + if (noinstall) + err = ports_create_port_noinstall (socketport_class, pfinet_bucket, + sizeof (struct sock_user), &user); + else + err = ports_create_port (socketport_class, pfinet_bucket, + sizeof (struct sock_user), &user); + if (err) + return 0; + + /* We maintain a reference count in `struct socket' (a member not + in the original Linux structure), because there can be multiple + ports (struct sock_user, aka protids) pointing to the same socket. + The socket lives until all the ports die. */ + ++sock->refcnt; + user->isroot = isroot; + user->sock = sock; + return user; +} + +/* This is called from the port cleanup function below, and on + a newly allocated socket when something went wrong in its creation. */ +void +sock_release (struct socket *sock) +{ + if (--sock->refcnt != 0) + return; + + if (sock->state != SS_UNCONNECTED) + sock->state = SS_DISCONNECTING; + + if (sock->ops) + sock->ops->release(sock, NULL); + + if (sock->identity != MACH_PORT_NULL) + mach_port_destroy (mach_task_self (), sock->identity); + + free (sock); +} + +/* Release the reference on the referenced socket. */ +void +clean_socketport (void *arg) +{ + struct sock_user *const user = arg; + + __mutex_lock (&global_lock); + sock_release (user->sock); + __mutex_unlock (&global_lock); +} diff --git a/pfinet/stubs.c b/pfinet/stubs.c new file mode 100644 index 00000000..e610cbc9 --- /dev/null +++ b/pfinet/stubs.c @@ -0,0 +1,70 @@ +/* Stub functions replacing things called from the Linux code + Copyright (C) 2000 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include "pfinet.h" + +#include +#include + +#include +#include +#include +#include + +int qdisc_restart(struct device *dev) +{ + return 0; +} + +void qdisc_run_queues(void) +{ +} + +struct Qdisc_head qdisc_head; +struct Qdisc qdisc_stub; + +void +dev_init_scheduler (struct device *dev) +{ + dev->qdisc = &qdisc_stub; +} +#pragma weak dev_shutdown = dev_init_scheduler +#pragma weak dev_activate = dev_init_scheduler +#pragma weak dev_deactivate = dev_init_scheduler +#pragma weak tcp_ioctl = dev_init_scheduler + +/* This isn't quite a stub, but it's not quite right either. */ +__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, + __u16 sport, __u16 dport) +{ + static u32 tcp_iss; + static time_t last; + struct timeval now; + + do_gettimeofday (&now); + + if (now.tv_sec - last > 300) + { + last = now.tv_sec; + srandom (getpid () ^ now.tv_sec ^ now.tv_usec); + tcp_iss = random (); + } + + return tcp_iss + (now.tv_sec * 1000000) + now.tv_usec; +} diff --git a/pfinet/timer-emul.c b/pfinet/timer-emul.c index d0842787..c305486e 100644 --- a/pfinet/timer-emul.c +++ b/pfinet/timer-emul.c @@ -41,7 +41,7 @@ timer_function (int this_is_a_pointless_variable_with_a_rather_long_name) timer_thread = mach_thread_self (); - mutex_lock (&global_lock); + __mutex_lock (&global_lock); while (1) { int jiff = jiffies; @@ -53,13 +53,13 @@ timer_function (int this_is_a_pointless_variable_with_a_rather_long_name) else wait = ((timers->expires - jiff) * 1000) / HZ; - mutex_unlock (&global_lock); + __mutex_unlock (&global_lock); mach_msg (NULL, (MACH_RCV_MSG | MACH_RCV_INTERRUPT | (wait == -1 ? 0 : MACH_RCV_TIMEOUT)), 0, 0, recv, wait, MACH_PORT_NULL); - mutex_lock (&global_lock); + __mutex_lock (&global_lock); while (timers->expires < jiffies) { @@ -69,10 +69,10 @@ timer_function (int this_is_a_pointless_variable_with_a_rather_long_name) timers = timers->next; if (timers) - timers->prevp = &timers; + timers->prev = &timers; tp->next = 0; - tp->prevp = 0; + tp->prev = 0; (*tp->function) (tp->data); } @@ -91,15 +91,15 @@ add_timer (struct timer_list *timer) if ((*tp)->expires > timer->expires) { timer->next = *tp; - timer->next->prevp = &timer->next; - timer->prevp = tp; + timer->next->prev = &timer->next; + timer->prev = tp; *tp = timer; break; } if (!*tp) { timer->next = 0; - timer->prevp = tp; + timer->prev = tp; *tp = timer; } @@ -122,20 +122,30 @@ add_timer (struct timer_list *timer) int del_timer (struct timer_list *timer) { - if (timer->prevp) + if (timer->prev) { - *timer->prevp = timer->next; + *timer->prev = timer->next; if (timer->next) - timer->next->prevp = timer->prevp; + timer->next->prev = timer->prev; timer->next = 0; - timer->prevp = 0; + timer->prev = 0; return 1; } else return 0; } +void +mod_timer (struct timer_list *timer, unsigned long expires) +{ + /* Should optimize this. */ + del_timer (timer); + timer->expires = expires; + add_timer (timer); +} + + void init_timer (struct timer_list *timer) { -- cgit v1.2.3