386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Tue, 24 Dec 1991 22:24:24 +0000 (14:24 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Tue, 24 Dec 1991 22:24:24 +0000 (14:24 -0800)
Work on file usr/src/sys.386bsd/i386/Makefile
Work on file usr/src/sys.386bsd/conf/param.c
Work on file usr/src/sys.386bsd/kern/init_sysent.c
Work on file usr/src/sys.386bsd/kern/kern_acct.c
Work on file usr/src/sys.386bsd/conf/defines
Work on file usr/src/sys.386bsd/kern/fifo_vnops.c
Work on file usr/src/sys.386bsd/kern/dead_vnops.c
Work on file usr/src/sys.386bsd/conf/nfsswapvmunix.c
Work on file usr/src/sys.386bsd/kern/sys_generic.c
Work on file usr/src/sys.386bsd/kern/kern_xxx.c
Work on file usr/src/sys.386bsd/kern/syscalls.c
Work on file usr/src/sys.386bsd/kern/kern_kinfo.c
Work on file usr/src/sys.386bsd/kern/kern_ktrace.c
Work on file usr/src/sys.386bsd/kern/subr_xxx.c
Work on file usr/src/sys.386bsd/kern/sys_socket.c
Work on file usr/src/sys.386bsd/kern/kern_time.c
Work on file usr/src/sys.386bsd/kern/tty_compat.c
Work on file usr/src/sys.386bsd/kern/vfs_cache.c
Work on file usr/src/sys.386bsd/kern/vfs_lookup.c
Work on file usr/src/sys.386bsd/kern/uipc_domain.c
Work on file usr/src/sys.386bsd/net/bpf.h
Work on file usr/src/sys.386bsd/kern/tty_tty.c
Work on file usr/src/sys.386bsd/kern/vfs_subr.c
Work on file usr/src/sys.386bsd/net/af.c
Work on file usr/src/sys.386bsd/kern/uipc_proto.c
Work on file usr/src/sys.386bsd/net/af.h
Work on file usr/src/sys.386bsd/kern/tty_conf.c
Work on file usr/src/sys.386bsd/kern/uipc_socket2.c
Work on file usr/src/sys.386bsd/kern/sysv_shm.c
Work on file usr/src/sys.386bsd/kern/tty_tb.c
Work on file usr/src/sys.386bsd/kern/uipc_socket.c
Work on file usr/src/sys.386bsd/net/radix.h
Work on file usr/src/sys.386bsd/net/if_arp.h
Work on file usr/src/sys.386bsd/net/route.c
Work on file usr/src/sys.386bsd/net/netisr.h
Work on file usr/src/sys.386bsd/net/if_llc.h
Work on file usr/src/sys.386bsd/net/raw_usrreq.c
Work on file usr/src/sys.386bsd/net/if_ethersubr.c
Work on file usr/src/sys.386bsd/net/if_dl.h
Work on file usr/src/sys.386bsd/net/bpf_filter.c
Work on file usr/src/sys.386bsd/net/raw_cb.c
Work on file usr/src/sys.386bsd/net/if_slvar.h
Work on file usr/src/sys.386bsd/net/if.c
Work on file usr/src/sys.386bsd/net/raw_cb.h
Work on file usr/src/sys.386bsd/net/if_types.h
Work on file usr/src/sys.386bsd/net/if_loop.c
Work on file usr/src/sys.386bsd/net/radix.c
Work on file usr/src/sys.386bsd/net/bpfdesc.h
Work on file usr/src/sys.386bsd/netinet/icmp_var.h
Work on file usr/src/sys.386bsd/net/slcompress.c
Work on file usr/src/sys.386bsd/net/slcompress.h
Work on file usr/src/sys.386bsd/net/route.h
Work on file usr/src/sys.386bsd/netinet/if_ether.h
Work on file usr/src/sys.386bsd/net/rtsock.c
Work on file usr/src/sys.386bsd/netinet/if_ether.c
Work on file usr/src/sys.386bsd/netinet/in_systm.h
Work on file usr/src/sys.386bsd/netinet/ip.h
Work on file usr/src/sys.386bsd/netinet/ip_icmp.c
Work on file usr/src/sys.386bsd/netinet/in_pcb.h
Work on file usr/src/sys.386bsd/netinet/in_pcb.c
Work on file usr/src/sys.386bsd/netinet/in_cksum.c
Work on file usr/src/sys.386bsd/netinet/in.c
Work on file usr/src/sys.386bsd/netinet/in.h
Work on file usr/src/sys.386bsd/netinet/in_var.h
Work on file usr/src/sys.386bsd/netinet/ip_icmp.h
Work on file usr/src/sys.386bsd/netinet/tcp_output.c
Work on file usr/src/sys.386bsd/netinet/tcp_fsm.h
Work on file usr/src/sys.386bsd/nfs/nfs_node.c
Work on file usr/src/sys.386bsd/netinet/udp.h
Work on file usr/src/sys.386bsd/netinet/udp_var.h
Work on file usr/src/sys.386bsd/netinet/tcp_debug.c
Work on file usr/src/sys.386bsd/netinet/tcp_usrreq.c
Work on file usr/src/sys.386bsd/nfs/nfs_serv.c
Work on file usr/src/sys.386bsd/netinet/tcp_seq.h
Work on file usr/src/sys.386bsd/netinet/tcp.h
Work on file usr/src/sys.386bsd/netinet/tcp_var.h
Work on file usr/src/sys.386bsd/netinet/ip_var.h
Work on file usr/src/sys.386bsd/netinet/tcp_subr.c
Work on file usr/src/sys.386bsd/netinet/tcp_timer.h
Work on file usr/src/sys.386bsd/netinet/tcp_timer.c
Work on file usr/src/sys.386bsd/netinet/tcpip.h
Work on file usr/src/sys.386bsd/nfs/nfs.h
Work on file usr/src/sys.386bsd/netinet/ip_input.c
Work on file usr/src/sys.386bsd/netinet/udp_usrreq.c
Work on file usr/src/sys.386bsd/netinet/tcp_debug.h
Work on file usr/src/sys.386bsd/nfs/nfs_bio.c
Work on file usr/src/sys.386bsd/netinet/ip_output.c
Work on file usr/src/sys.386bsd/netinet/tcp_input.c
Work on file usr/src/sys.386bsd/nfs/nfs_vfsops.c
Work on file usr/src/sys.386bsd/sys/cdefs.h
Work on file usr/src/sys.386bsd/stand/stat.c
Work on file usr/src/sys.386bsd/stand/saioctl.h
Work on file usr/src/sys.386bsd/nfs/nfscompress.h
Work on file usr/src/sys.386bsd/stand/dev.c
Work on file usr/src/sys.386bsd/nfs/xdr_subs.h
Work on file usr/src/sys.386bsd/stand/cat.c
Work on file usr/src/sys.386bsd/nfs/nfsdiskless.h
Work on file usr/src/sys.386bsd/nfs/nfsm_subs.h
Work on file usr/src/sys.386bsd/stand/copy.c
Work on file usr/src/sys.386bsd/nfs/nfsiom.h
Work on file usr/src/sys.386bsd/nfs/nfsrvcache.h
Work on file usr/src/sys.386bsd/nfs/nfs_srvcache.c
Work on file usr/src/sys.386bsd/sys/callout.h
Work on file usr/src/sys.386bsd/nfs/nfsv2.h
Work on file usr/src/sys.386bsd/nfs/nfs_socket.c
Work on file usr/src/sys.386bsd/sys/acct.h
Work on file usr/src/sys.386bsd/sys/clist.h
Work on file usr/src/sys.386bsd/stand/saerrno.h
Work on file usr/src/sys.386bsd/nfs/rpcv2.h
Work on file usr/src/sys.386bsd/stand/ls.c
Work on file usr/src/sys.386bsd/nfs/nfs_syscalls.c
Work on file usr/src/sys.386bsd/nfs/nfsmount.h
Work on file usr/src/sys.386bsd/nfs/nfsnode.h
Work on file usr/src/sys.386bsd/sys/dkstat.h
Work on file usr/src/sys.386bsd/sys/dkbad.h
Work on file usr/src/sys.386bsd/sys/conf.h
Work on file usr/src/sys.386bsd/sys/filedesc.h
Work on file usr/src/sys.386bsd/sys/exec.h
Work on file usr/src/sys.386bsd/sys/file.h
Work on file usr/src/sys.386bsd/sys/fcntl.h
Work on file usr/src/sys.386bsd/sys/domain.h
Work on file usr/src/sys.386bsd/sys/errno.h
Work on file usr/src/sys.386bsd/sys/fifo.h
Work on file usr/src/sys.386bsd/sys/dir.h
Work on file usr/src/sys.386bsd/sys/dmap.h
Work on file usr/src/sys.386bsd/sys/mtio.h
Work on file usr/src/sys.386bsd/sys/kinfo_proc.h
Work on file usr/src/sys.386bsd/sys/ioctl.h
Work on file usr/src/sys.386bsd/sys/msgbuf.h
Work on file usr/src/sys.386bsd/sys/mbuf.h
Work on file usr/src/sys.386bsd/sys/kinfo.h
Work on file usr/src/sys.386bsd/sys/malloc.h
Work on file usr/src/sys.386bsd/sys/mapmem.h
Work on file usr/src/sys.386bsd/sys/ptrace.h
Work on file usr/src/sys.386bsd/sys/ktrace.h
Work on file usr/src/sys.386bsd/sys/proc.h
Work on file usr/src/sys.386bsd/sys/mman.h
Work on file usr/src/sys.386bsd/sys/kernel.h
Work on file usr/src/sys.386bsd/sys/namei.h
Work on file usr/src/sys.386bsd/sys/ipc.h
Work on file usr/src/sys.386bsd/sys/ioctl_compat.h
Work on file usr/src/sys.386bsd/sys/protosw.h
Work on file usr/src/sys.386bsd/sys/gprof.h
Work on file usr/src/sys.386bsd/sys/systm.h
Work on file usr/src/sys.386bsd/sys/stat.h
Work on file usr/src/sys.386bsd/sys/socket.h
Work on file usr/src/sys.386bsd/sys/timeb.h
Work on file usr/src/sys.386bsd/sys/shm.h
Work on file usr/src/sys.386bsd/sys/socketvar.h
Work on file usr/src/sys.386bsd/sys/syslimits.h
Work on file usr/src/sys.386bsd/sys/specdev.h
Work on file usr/src/sys.386bsd/sys/time.h
Work on file usr/src/sys.386bsd/sys/resource.h
Work on file usr/src/sys.386bsd/sys/syscall.h
Work on file usr/src/sys.386bsd/sys/tablet.h
Work on file usr/src/sys.386bsd/sys/termios.h
Work on file usr/src/sys.386bsd/sys/reboot.h
Work on file usr/src/sys.386bsd/sys/syslog.h
Work on file usr/src/sys.386bsd/sys/signalvar.h
Work on file usr/src/sys.386bsd/sys/vadvise.h
Work on file usr/src/sys.386bsd/sys/ttychars.h
Work on file usr/src/sys.386bsd/sys/ttydefaults.h
Work on file usr/src/sys.386bsd/sys/trace.h
Work on file usr/src/sys.386bsd/sys/times.h
Work on file usr/src/sys.386bsd/sys/user.h
Work on file usr/src/sys.386bsd/sys/un.h
Work on file usr/src/sys.386bsd/sys/uio.h
Work on file usr/src/sys.386bsd/sys/unistd.h
Work on file usr/src/sys.386bsd/sys/ttydev.h
Work on file usr/src/sys.386bsd/sys/tprintf.h
Work on file usr/src/sys.386bsd/sys/vlimit.h
Work on file usr/src/sys.386bsd/sys/types.h
Work on file usr/src/sys.386bsd/sys/ucred.h
Work on file usr/src/sys.386bsd/sys/unpcb.h
Work on file usr/src/sys.386bsd/sys/vcmd.h
Work on file usr/src/sys.386bsd/sys/vmmeter.h
Work on file usr/src/sys.386bsd/sys/vnode.h
Work on file usr/src/sys.386bsd/ufs/mfsiom.h
Work on file usr/src/sys.386bsd/ufs/fs.h
Work on file usr/src/sys.386bsd/ufs/lockf.h
Work on file usr/src/sys.386bsd/sys/vsio.h
Work on file usr/src/sys.386bsd/ufs/dinode.h
Work on file usr/src/sys.386bsd/ufs/ufs_alloc.c
Work on file usr/src/sys.386bsd/ufs/inode.h
Work on file usr/src/sys.386bsd/ufs/ufs_bmap.c
Work on file usr/src/sys.386bsd/ufs/mfs_vfsops.c
Work on file usr/src/sys.386bsd/sys/wait.h
Work on file usr/src/sys.386bsd/sys/vtimes.h
Work on file usr/src/sys.386bsd/ufs/dir.h
Work on file usr/src/sys.386bsd/ufs/mfsnode.h
Work on file usr/src/sys.386bsd/ufs/ufs_inode.c
Work on file usr/src/sys.386bsd/ufs/quota.h
Work on file usr/src/sys.386bsd/ufs/ufs_subr.c
Work on file usr/src/sys.386bsd/ufs/ufsmount.h
Work on file usr/src/sys.386bsd/ufs/ufs_quota.c
Work on file usr/src/sys.386bsd/ufs/ufs_vnops.c
Work on file usr/src/sys.386bsd/ufs/ufs_tables.c
Work on file usr/src/sys.386bsd/vm/device_pager.h
Work on file usr/src/sys.386bsd/vm/vm_pager.h
Work on file usr/src/sys.386bsd/vm/vm_object.c
Work on file usr/src/sys.386bsd/vm/vm_pager.c
Work on file usr/src/sys.386bsd/vm/lock.h
Work on file usr/src/sys.386bsd/vm/swap_pager.h
Work on file usr/src/sys.386bsd/vm/vm_param.h
Work on file usr/src/sys.386bsd/vm/vm_inherit.h
Work on file usr/src/sys.386bsd/vm/vm_init.c
Work on file usr/src/sys.386bsd/vm/vm_pageout.c
Work on file usr/src/sys.386bsd/vm/vm.h
Work on file usr/src/sys.386bsd/vm/vm_map.h
Work on file usr/src/sys.386bsd/vm/vm_prot.h
Work on file usr/src/sys.386bsd/vm/vm_pageout.h
Work on file usr/src/sys.386bsd/vm/vm_statistics.h
Work on file usr/src/sys.386bsd/vm/kern_lock.c
Work on file usr/src/sys.386bsd/vm/queue.h
Work on file usr/src/sys.386bsd/vm/vm_object.h
Work on file usr/src/sys.386bsd/vm/vm_page.h
Work on file usr/src/sys.386bsd/vm/pmap.h
Work on file usr/src/sys.386bsd/vm/vm_meter.c
Work on file usr/src/sys.386bsd/vm/vm_user.c
Work on file usr/src/sys.386bsd/vm/vnode_pager.h
Work on file usr/src/sys.386bsd/vm/vm_user.h
Work on file usr/src/sys.386bsd/vm/vnode_pager.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

222 files changed:
usr/src/sys.386bsd/conf/defines [new file with mode: 0644]
usr/src/sys.386bsd/conf/nfsswapvmunix.c [new file with mode: 0644]
usr/src/sys.386bsd/conf/param.c [new file with mode: 0644]
usr/src/sys.386bsd/i386/Makefile [new file with mode: 0644]
usr/src/sys.386bsd/kern/dead_vnops.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/fifo_vnops.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/init_sysent.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/kern_acct.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/kern_kinfo.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/kern_ktrace.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/kern_time.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/kern_xxx.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/subr_xxx.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/sys_generic.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/sys_socket.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/syscalls.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/sysv_shm.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/tty_compat.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/tty_conf.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/tty_tb.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/tty_tty.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/uipc_domain.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/uipc_proto.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/uipc_socket.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/uipc_socket2.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/vfs_cache.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/vfs_lookup.c [new file with mode: 0644]
usr/src/sys.386bsd/kern/vfs_subr.c [new file with mode: 0644]
usr/src/sys.386bsd/net/af.c [new file with mode: 0644]
usr/src/sys.386bsd/net/af.h [new file with mode: 0644]
usr/src/sys.386bsd/net/bpf.h [new file with mode: 0644]
usr/src/sys.386bsd/net/bpf_filter.c [new file with mode: 0644]
usr/src/sys.386bsd/net/bpfdesc.h [new file with mode: 0644]
usr/src/sys.386bsd/net/if.c [new file with mode: 0644]
usr/src/sys.386bsd/net/if_arp.h [new file with mode: 0644]
usr/src/sys.386bsd/net/if_dl.h [new file with mode: 0644]
usr/src/sys.386bsd/net/if_ethersubr.c [new file with mode: 0644]
usr/src/sys.386bsd/net/if_llc.h [new file with mode: 0644]
usr/src/sys.386bsd/net/if_loop.c [new file with mode: 0644]
usr/src/sys.386bsd/net/if_slvar.h [new file with mode: 0644]
usr/src/sys.386bsd/net/if_types.h [new file with mode: 0644]
usr/src/sys.386bsd/net/netisr.h [new file with mode: 0644]
usr/src/sys.386bsd/net/radix.c [new file with mode: 0644]
usr/src/sys.386bsd/net/radix.h [new file with mode: 0644]
usr/src/sys.386bsd/net/raw_cb.c [new file with mode: 0644]
usr/src/sys.386bsd/net/raw_cb.h [new file with mode: 0644]
usr/src/sys.386bsd/net/raw_usrreq.c [new file with mode: 0644]
usr/src/sys.386bsd/net/route.c [new file with mode: 0644]
usr/src/sys.386bsd/net/route.h [new file with mode: 0644]
usr/src/sys.386bsd/net/rtsock.c [new file with mode: 0644]
usr/src/sys.386bsd/net/slcompress.c [new file with mode: 0644]
usr/src/sys.386bsd/net/slcompress.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/icmp_var.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/if_ether.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/if_ether.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/in.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/in.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/in_cksum.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/in_pcb.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/in_pcb.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/in_systm.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/in_var.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/ip.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/ip_icmp.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/ip_icmp.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/ip_input.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/ip_output.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/ip_var.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_debug.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_debug.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_fsm.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_input.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_output.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_seq.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_subr.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_timer.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_timer.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_usrreq.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcp_var.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/tcpip.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/udp.h [new file with mode: 0644]
usr/src/sys.386bsd/netinet/udp_usrreq.c [new file with mode: 0644]
usr/src/sys.386bsd/netinet/udp_var.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs_bio.c [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs_node.c [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs_serv.c [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs_socket.c [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs_srvcache.c [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs_syscalls.c [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfs_vfsops.c [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfscompress.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfsdiskless.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfsiom.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfsm_subs.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfsmount.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfsnode.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfsrvcache.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/nfsv2.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/rpcv2.h [new file with mode: 0644]
usr/src/sys.386bsd/nfs/xdr_subs.h [new file with mode: 0644]
usr/src/sys.386bsd/stand/cat.c [new file with mode: 0644]
usr/src/sys.386bsd/stand/copy.c [new file with mode: 0644]
usr/src/sys.386bsd/stand/dev.c [new file with mode: 0644]
usr/src/sys.386bsd/stand/ls.c [new file with mode: 0644]
usr/src/sys.386bsd/stand/saerrno.h [new file with mode: 0644]
usr/src/sys.386bsd/stand/saioctl.h [new file with mode: 0644]
usr/src/sys.386bsd/stand/stat.c [new file with mode: 0644]
usr/src/sys.386bsd/sys/acct.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/callout.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/cdefs.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/clist.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/conf.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/dir.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/dkbad.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/dkstat.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/dmap.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/domain.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/errno.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/exec.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/fcntl.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/fifo.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/file.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/filedesc.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/gprof.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ioctl.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ioctl_compat.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ipc.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/kernel.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/kinfo.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/kinfo_proc.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ktrace.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/malloc.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/mapmem.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/mbuf.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/mman.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/msgbuf.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/mtio.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/namei.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/proc.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/protosw.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ptrace.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/reboot.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/resource.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/shm.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/signalvar.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/socket.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/socketvar.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/specdev.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/stat.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/syscall.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/syslimits.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/syslog.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/systm.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/tablet.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/termios.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/time.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/timeb.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/times.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/tprintf.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/trace.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ttychars.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ttydefaults.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ttydev.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/types.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/ucred.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/uio.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/un.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/unistd.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/unpcb.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/user.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/vadvise.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/vcmd.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/vlimit.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/vmmeter.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/vnode.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/vsio.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/vtimes.h [new file with mode: 0644]
usr/src/sys.386bsd/sys/wait.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/dinode.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/dir.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/fs.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/inode.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/lockf.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/mfs_vfsops.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/mfsiom.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/mfsnode.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/quota.h [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufs_alloc.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufs_bmap.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufs_inode.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufs_quota.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufs_subr.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufs_tables.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufs_vnops.c [new file with mode: 0644]
usr/src/sys.386bsd/ufs/ufsmount.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/device_pager.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/kern_lock.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/lock.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/pmap.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/queue.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/swap_pager.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_inherit.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_init.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_map.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_meter.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_object.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_object.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_page.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_pageout.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_pageout.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_pager.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_pager.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_param.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_prot.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_statistics.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_user.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/vm_user.h [new file with mode: 0644]
usr/src/sys.386bsd/vm/vnode_pager.c [new file with mode: 0644]
usr/src/sys.386bsd/vm/vnode_pager.h [new file with mode: 0644]

diff --git a/usr/src/sys.386bsd/conf/defines b/usr/src/sys.386bsd/conf/defines
new file mode 100644 (file)
index 0000000..ea70463
--- /dev/null
@@ -0,0 +1,15 @@
+/:#if.*[ \t]*KPROF/d
+/:#if.*[ \t]*PGINPROF/d
+/:#if.*[ \t]*UNFAST/d
+/:#if.*[ \t]*INSECURE/d
+/:#if.*[ \t]*TRACE/d
+/:#if.*[ \t]*DISKMON/d
+/:#if.*[ \t]*INTRLVE/d
+/:#if.*[ \t]*lint/d
+/:#if.*[ \t]*notdef/d
+/:#if.*[ \t]*unneeded/d
+/:#if.*[ \t]*vax/d
+/:#if.*[ \t]*TCPTRUEOOB/d
+/:#if.*[ \t]*irele/d
+/:#if.*[ \t]*ilock/d
+/:#if.*[ \t]*notyet/d
diff --git a/usr/src/sys.386bsd/conf/nfsswapvmunix.c b/usr/src/sys.386bsd/conf/nfsswapvmunix.c
new file mode 100644 (file)
index 0000000..3ca040a
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsswapvmunix.c     7.1 (Berkeley) 3/4/91
+ */
+
+/*
+ * Sample NFS swapvmunix configuration file.
+ * This should be filled in by the bootstrap program.
+ * See /sys/nfs/nfsdiskless.h for details of the fields.
+ */
+
+#include "../sys/param.h"
+#include "../sys/conf.h"
+#include "../sys/socket.h"
+#include "../sys/mount.h"
+#include "../net/if.h"
+#include "../nfs/nfsv2.h"
+#include "../nfs/nfsdiskless.h"
+
+extern int nfs_mountroot();
+int (*mountroot)() = nfs_mountroot;
+
+dev_t  rootdev = NODEV;
+dev_t  argdev  = NODEV;
+dev_t  dumpdev = NODEV;
+
+struct swdevt swdevt[] = {
+       { NODEV,        0,      5000 }, /* happy:/u/swap.dopey  */
+       { 0, 0, 0 }
+};
+struct nfs_diskless nfs_diskless = {
+       { { 'q', 'e', '0', '\0' },
+         { 0x10, 0x2, { 0x0, 0x0, 0x83, 0x68, 0x30, 0x2, } },
+         { 0x10, 0x2, { 0x0, 0x0, 0x83, 0x68, 0x30, 0xff, } },
+         { 0x10, 0x0, { 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, } },
+       },
+       { 0x10, 0x2, { 0x0, 0x0, 0x83, 0x68, 0x30, 0x12, } },
+       {
+         (struct sockaddr *)0, SOCK_DGRAM, 0, (nfsv2fh_t *)0,
+         0, 8192, 8192, 10, 100, (char *)0,
+       },
+       {
+               0xf,
+               0x9,
+               0x0,
+               0x0,
+               0x1,
+               0x0,
+               0x0,
+               0x0,
+               0xc,
+               0x0,
+               0x0,
+               0x0,
+               0x6,
+               0x0,
+               0x0,
+               0x0,
+               0x27,
+               0x18,
+               0x79,
+               0x27,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+       },
+       { 0x10, 0x2, { 0x8, 0x1, 0x83, 0x68, 0x30, 0x5, } },
+       "happy",
+       {
+         (struct sockaddr *)0, SOCK_DGRAM, 0, (nfsv2fh_t *)0,
+         0, 8192, 8192, 10, 100, (char *)0,
+       },
+       {
+               0x0,
+               0x9,
+               0x0,
+               0x0,
+               0x1,
+               0x0,
+               0x0,
+               0x0,
+               0xc,
+               0x0,
+               0x0,
+               0x0,
+               0x2,
+               0x0,
+               0x0,
+               0x0,
+               0xd0,
+               0x48,
+               0x42,
+               0x25,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+               0x0,
+       },
+       { 0x10, 0x2, { 0x8, 0x1, 0x83, 0x68, 0x30, 0x5, } },
+       "happy",
+};
diff --git a/usr/src/sys.386bsd/conf/param.c b/usr/src/sys.386bsd/conf/param.c
new file mode 100644 (file)
index 0000000..6444f96
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 1980, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)param.c     7.20 (Berkeley) 6/27/91
+ */
+
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/socket.h"
+#include "sys/proc.h"
+#include "sys/vnode.h"
+#include "sys/file.h"
+#include "sys/callout.h"
+#include "sys/clist.h"
+#include "sys/mbuf.h"
+#include "ufs/quota.h"
+#include "sys/kernel.h"
+#ifdef SYSVSHM
+#include "machine/vmparam.h"
+#include "sys/shm.h"
+#endif
+
+/*
+ * System parameter formulae.
+ *
+ * This file is copied into each directory where we compile
+ * the kernel; it should be modified there to suit local taste
+ * if necessary.
+ *
+ * Compiled with -DHZ=xx -DTIMEZONE=x -DDST=x -DMAXUSERS=xx
+ */
+
+#ifndef HZ
+#define        HZ 100
+#endif
+int    hz = HZ;
+int    tick = 1000000 / HZ;
+int    tickadj = 240000 / (60 * HZ);           /* can adjust 240ms in 60s */
+struct timezone tz = { TIMEZONE, DST };
+#define        NPROC (20 + 16 * MAXUSERS)
+int    maxproc = NPROC;
+#define        NTEXT (80 + NPROC / 8)                  /* actually the object cache */
+#define        NVNODE (NPROC + NTEXT + 100)
+long   desiredvnodes = NVNODE;
+int    maxfiles = 3 * (NPROC + MAXUSERS) + 80;
+int    ncallout = 16 + NPROC;
+int    nclist = 60 + 12 * MAXUSERS;
+int    nmbclusters = NMBCLUSTERS;
+int    fscale = FSCALE;        /* kernel uses `FSCALE', user uses `fscale' */
+
+/*
+ * Values in support of System V compatible shared memory.     XXX
+ */
+#ifdef SYSVSHM
+#define        SHMMAX  (SHMMAXPGS*NBPG)
+#define        SHMMIN  1
+#define        SHMMNI  32                      /* <= SHMMMNI in shm.h */
+#define        SHMSEG  8
+#define        SHMALL  (SHMMAXPGS/CLSIZE)
+
+struct shminfo shminfo = {
+       SHMMAX,
+       SHMMIN,
+       SHMMNI,
+       SHMSEG,
+       SHMALL
+};
+#endif
+
+/*
+ * These are initialized at bootstrap time
+ * to values dependent on memory size
+ */
+int    nbuf, nswbuf;
+
+/*
+ * These have to be allocated somewhere; allocating
+ * them here forces loader errors if this file is omitted
+ * (if they've been externed everywhere else; hah!).
+ */
+struct         callout *callout;
+struct cblock *cfree;
+struct buf *buf, *swbuf;
+char   *buffers;
+
+/*
+ * Proc/pgrp hashing.
+ * Here so that hash table sizes can depend on MAXUSERS/NPROC.
+ * Hash size must be a power of two.
+ * NOW omission of this file will cause loader errors!
+ */
+
+#if NPROC > 1024
+#define        PIDHSZ          512
+#else
+#if NPROC > 512
+#define        PIDHSZ          256
+#else
+#if NPROC > 256
+#define        PIDHSZ          128
+#else
+#define        PIDHSZ          64
+#endif
+#endif
+#endif
+
+struct proc *pidhash[PIDHSZ];
+struct pgrp *pgrphash[PIDHSZ];
+int    pidhashmask = PIDHSZ - 1;
diff --git a/usr/src/sys.386bsd/i386/Makefile b/usr/src/sys.386bsd/i386/Makefile
new file mode 100644 (file)
index 0000000..0662e28
--- /dev/null
@@ -0,0 +1,24 @@
+#      @(#)Makefile    7.3 (Berkeley) 6/9/91
+
+# Makefile for i386 tags file
+
+all:
+       @echo "make tags or links only"
+
+TI386= ../i386/tags
+SI386= ../i386/i386/*.[ch] ../i386/include/*.h ../i386/isa/*.[ch]
+AI386= ../i386/i386/*.s
+
+# Directories in which to place i386 tags links
+DI386= eisa isa mca include
+
+tags:
+       -ctags -dtf ${TI386} ${COMM} ${SI386}
+       egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${AI386} | \
+           sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \
+               >> ${TI386}
+       sort -o ${TI386} ${TI386}
+
+links:
+       -for i in ${DI386}; do \
+           cd $$i && rm -f tags; ln -s ../tags tags; done
diff --git a/usr/src/sys.386bsd/kern/dead_vnops.c b/usr/src/sys.386bsd/kern/dead_vnops.c
new file mode 100644 (file)
index 0000000..e1430bc
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dead_vnops.c        7.13 (Berkeley) 4/15/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "vnode.h"
+#include "errno.h"
+#include "namei.h"
+#include "buf.h"
+
+/*
+ * Prototypes for dead operations on vnodes.
+ */
+int    dead_badop(),
+       dead_ebadf();
+int    dead_lookup __P((
+               struct vnode *vp,
+               struct nameidata *ndp,
+               struct proc *p));
+#define dead_create ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) dead_badop)
+#define dead_mknod ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) dead_badop)
+int    dead_open __P((
+               struct vnode *vp,
+               int mode,
+               struct ucred *cred,
+               struct proc *p));
+#define dead_close ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflag, \
+               struct ucred *cred, \
+               struct proc *p))) nullop)
+#define dead_access ((int (*) __P(( \
+               struct vnode *vp, \
+               int mode, \
+               struct ucred *cred, \
+               struct proc *p))) dead_ebadf)
+#define dead_getattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) dead_ebadf)
+#define dead_setattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) dead_ebadf)
+int    dead_read __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+int    dead_write __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+int    dead_ioctl __P((
+               struct vnode *vp,
+               int command,
+               caddr_t data,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+int    dead_select __P((
+               struct vnode *vp,
+               int which,
+               int fflags,
+               struct ucred *cred,
+               struct proc *p));
+#define dead_mmap ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               struct proc *p))) dead_badop)
+#define dead_fsync ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               int waitfor, \
+               struct proc *p))) nullop)
+#define dead_seek ((int (*) __P(( \
+               struct vnode *vp, \
+               off_t oldoff, \
+               off_t newoff, \
+               struct ucred *cred))) nullop)
+#define dead_remove ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) dead_badop)
+#define dead_link ((int (*) __P(( \
+               struct vnode *vp, \
+               struct nameidata *ndp, \
+               struct proc *p))) dead_badop)
+#define dead_rename ((int (*) __P(( \
+               struct nameidata *fndp, \
+               struct nameidata *tdnp, \
+               struct proc *p))) dead_badop)
+#define dead_mkdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) dead_badop)
+#define dead_rmdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) dead_badop)
+#define dead_symlink ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               char *target, \
+               struct proc *p))) dead_badop)
+#define dead_readdir ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred, \
+               int *eofflagp))) dead_ebadf)
+#define dead_readlink ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred))) dead_ebadf)
+#define dead_abortop ((int (*) __P(( \
+               struct nameidata *ndp))) dead_badop)
+#define dead_inactive ((int (*) __P(( \
+               struct vnode *vp, \
+               struct proc *p))) nullop)
+#define dead_reclaim ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+int    dead_lock __P((
+               struct vnode *vp));
+#define dead_unlock ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+int    dead_bmap __P((
+               struct vnode *vp,
+               daddr_t bn,
+               struct vnode **vpp,
+               daddr_t *bnp));
+int    dead_strategy __P((
+               struct buf *bp));
+int    dead_print __P((
+               struct vnode *vp));
+#define dead_islocked ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+#define dead_advlock ((int (*) __P(( \
+               struct vnode *vp, \
+               caddr_t id, \
+               int op, \
+               struct flock *fl, \
+               int flags))) dead_ebadf)
+
+struct vnodeops dead_vnodeops = {
+       dead_lookup,    /* lookup */
+       dead_create,    /* create */
+       dead_mknod,     /* mknod */
+       dead_open,      /* open */
+       dead_close,     /* close */
+       dead_access,    /* access */
+       dead_getattr,   /* getattr */
+       dead_setattr,   /* setattr */
+       dead_read,      /* read */
+       dead_write,     /* write */
+       dead_ioctl,     /* ioctl */
+       dead_select,    /* select */
+       dead_mmap,      /* mmap */
+       dead_fsync,     /* fsync */
+       dead_seek,      /* seek */
+       dead_remove,    /* remove */
+       dead_link,      /* link */
+       dead_rename,    /* rename */
+       dead_mkdir,     /* mkdir */
+       dead_rmdir,     /* rmdir */
+       dead_symlink,   /* symlink */
+       dead_readdir,   /* readdir */
+       dead_readlink,  /* readlink */
+       dead_abortop,   /* abortop */
+       dead_inactive,  /* inactive */
+       dead_reclaim,   /* reclaim */
+       dead_lock,      /* lock */
+       dead_unlock,    /* unlock */
+       dead_bmap,      /* bmap */
+       dead_strategy,  /* strategy */
+       dead_print,     /* print */
+       dead_islocked,  /* islocked */
+       dead_advlock,   /* advlock */
+};
+
+/*
+ * Trivial lookup routine that always fails.
+ */
+/* ARGSUSED */
+dead_lookup(vp, ndp, p)
+       struct vnode *vp;
+       struct nameidata *ndp;
+       struct proc *p;
+{
+
+       ndp->ni_dvp = vp;
+       ndp->ni_vp = NULL;
+       return (ENOTDIR);
+}
+
+/*
+ * Open always fails as if device did not exist.
+ */
+/* ARGSUSED */
+dead_open(vp, mode, cred, p)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
+       struct proc *p;
+{
+
+       return (ENXIO);
+}
+
+/*
+ * Vnode op for read
+ */
+/* ARGSUSED */
+dead_read(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+
+       if (chkvnlock(vp))
+               panic("dead_read: lock");
+       /*
+        * Return EOF for character devices, EIO for others
+        */
+       if (vp->v_type != VCHR)
+               return (EIO);
+       return (0);
+}
+
+/*
+ * Vnode op for write
+ */
+/* ARGSUSED */
+dead_write(vp, uio, ioflag, cred)
+       register struct vnode *vp;
+       struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+
+       if (chkvnlock(vp))
+               panic("dead_write: lock");
+       return (EIO);
+}
+
+/*
+ * Device ioctl operation.
+ */
+/* ARGSUSED */
+dead_ioctl(vp, com, data, fflag, cred, p)
+       struct vnode *vp;
+       register int com;
+       caddr_t data;
+       int fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+
+       if (!chkvnlock(vp))
+               return (EBADF);
+       return (VOP_IOCTL(vp, com, data, fflag, cred, p));
+}
+
+/* ARGSUSED */
+dead_select(vp, which, fflags, cred, p)
+       struct vnode *vp;
+       int which, fflags;
+       struct ucred *cred;
+       struct proc *p;
+{
+
+       /*
+        * Let the user find out that the descriptor is gone.
+        */
+       return (1);
+}
+
+/*
+ * Just call the device strategy routine
+ */
+dead_strategy(bp)
+       register struct buf *bp;
+{
+
+       if (bp->b_vp == NULL || !chkvnlock(bp->b_vp)) {
+               bp->b_flags |= B_ERROR;
+               biodone(bp);
+               return (EIO);
+       }
+       return (VOP_STRATEGY(bp));
+}
+
+/*
+ * Wait until the vnode has finished changing state.
+ */
+dead_lock(vp)
+       struct vnode *vp;
+{
+
+       if (!chkvnlock(vp))
+               return (0);
+       return (VOP_LOCK(vp));
+}
+
+/*
+ * Wait until the vnode has finished changing state.
+ */
+dead_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+
+       if (!chkvnlock(vp))
+               return (EIO);
+       return (VOP_BMAP(vp, bn, vpp, bnp));
+}
+
+/*
+ * Print out the contents of a dead vnode.
+ */
+/* ARGSUSED */
+dead_print(vp)
+       struct vnode *vp;
+{
+
+       printf("tag VT_NON, dead vnode\n");
+}
+
+/*
+ * Empty vnode failed operation
+ */
+dead_ebadf()
+{
+
+       return (EBADF);
+}
+
+/*
+ * Empty vnode bad operation
+ */
+dead_badop()
+{
+
+       panic("dead_badop called");
+       /* NOTREACHED */
+}
+
+/*
+ * Empty vnode null operation
+ */
+dead_nullop()
+{
+
+       return (0);
+}
+
+/*
+ * We have to wait during times when the vnode is
+ * in a state of change.
+ */
+chkvnlock(vp)
+       register struct vnode *vp;
+{
+       int locked = 0;
+
+       while (vp->v_flag & VXLOCK) {
+               vp->v_flag |= VXWANT;
+               sleep((caddr_t)vp, PINOD);
+               locked = 1;
+       }
+       return (locked);
+}
diff --git a/usr/src/sys.386bsd/kern/fifo_vnops.c b/usr/src/sys.386bsd/kern/fifo_vnops.c
new file mode 100644 (file)
index 0000000..852b50d
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)fifo_vnops.c        7.7 (Berkeley) 4/15/91
+ */
+
+#include "param.h"
+#include "time.h"
+#include "namei.h"
+#include "vnode.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "stat.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "file.h"
+#include "fifo.h"
+#include "errno.h"
+#include "malloc.h"
+
+/*
+ * This structure is associated with the FIFO vnode and stores
+ * the state associated with the FIFO.
+ */
+struct fifoinfo {
+       struct socket   *fi_readsock;
+       struct socket   *fi_writesock;
+       long            fi_readers;
+       long            fi_writers;
+};
+
+struct vnodeops fifo_vnodeops = {
+       fifo_lookup,            /* lookup */
+       fifo_create,            /* create */
+       fifo_mknod,             /* mknod */
+       fifo_open,              /* open */
+       fifo_close,             /* close */
+       fifo_access,            /* access */
+       fifo_getattr,           /* getattr */
+       fifo_setattr,           /* setattr */
+       fifo_read,              /* read */
+       fifo_write,             /* write */
+       fifo_ioctl,             /* ioctl */
+       fifo_select,            /* select */
+       fifo_mmap,              /* mmap */
+       fifo_fsync,             /* fsync */
+       fifo_seek,              /* seek */
+       fifo_remove,            /* remove */
+       fifo_link,              /* link */
+       fifo_rename,            /* rename */
+       fifo_mkdir,             /* mkdir */
+       fifo_rmdir,             /* rmdir */
+       fifo_symlink,           /* symlink */
+       fifo_readdir,           /* readdir */
+       fifo_readlink,          /* readlink */
+       fifo_abortop,           /* abortop */
+       fifo_inactive,          /* inactive */
+       fifo_reclaim,           /* reclaim */
+       fifo_lock,              /* lock */
+       fifo_unlock,            /* unlock */
+       fifo_bmap,              /* bmap */
+       fifo_strategy,          /* strategy */
+       fifo_print,             /* print */
+       fifo_islocked,          /* islocked */
+       fifo_advlock,           /* advlock */
+};
+
+/*
+ * Trivial lookup routine that always fails.
+ */
+/* ARGSUSED */
+fifo_lookup(vp, ndp, p)
+       struct vnode *vp;
+       struct nameidata *ndp;
+       struct proc *p;
+{
+
+       ndp->ni_dvp = vp;
+       ndp->ni_vp = NULL;
+       return (ENOTDIR);
+}
+
+/*
+ * Open called to set up a new instance of a fifo or
+ * to find an active instance of a fifo.
+ */
+/* ARGSUSED */
+fifo_open(vp, mode, cred, p)
+       register struct vnode *vp;
+       int mode;
+       struct ucred *cred;
+       struct proc *p;
+{
+       register struct fifoinfo *fip;
+       struct socket *rso, *wso;
+       int error;
+       static char openstr[] = "fifo";
+
+       if ((mode & (FREAD|FWRITE)) == (FREAD|FWRITE))
+               return (EINVAL);
+       if ((fip = vp->v_fifoinfo) == NULL) {
+               MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
+               vp->v_fifoinfo = fip;
+               if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) {
+                       free(fip, M_VNODE);
+                       vp->v_fifoinfo = NULL;
+                       return (error);
+               }
+               fip->fi_readsock = rso;
+               if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) {
+                       (void)soclose(rso);
+                       free(fip, M_VNODE);
+                       vp->v_fifoinfo = NULL;
+                       return (error);
+               }
+               fip->fi_writesock = wso;
+               if (error = unp_connect2(wso, rso)) {
+                       (void)soclose(wso);
+                       (void)soclose(rso);
+                       free(fip, M_VNODE);
+                       vp->v_fifoinfo = NULL;
+                       return (error);
+               }
+               wso->so_state |= SS_CANTRCVMORE;
+               rso->so_state |= SS_CANTSENDMORE;
+       }
+       error = 0;
+       if (mode & FREAD) {
+               fip->fi_readers++;
+               if (fip->fi_readers == 1) {
+                       fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
+                       if (fip->fi_writers > 0)
+                               wakeup((caddr_t)&fip->fi_writers);
+               }
+               if (mode & O_NONBLOCK)
+                       return (0);
+               while (fip->fi_writers == 0)
+                       if (error = tsleep((caddr_t)&fip->fi_readers, PSOCK,
+                           openstr, 0))
+                               break;
+       } else {
+               fip->fi_writers++;
+               if (fip->fi_readers == 0 && (mode & O_NONBLOCK)) {
+                       error = ENXIO;
+               } else {
+                       if (fip->fi_writers == 1) {
+                               fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
+                               if (fip->fi_readers > 0)
+                                       wakeup((caddr_t)&fip->fi_readers);
+                       }
+                       while (fip->fi_readers == 0)
+                               if (error = tsleep((caddr_t)&fip->fi_writers,
+                                   PSOCK, openstr, 0))
+                                       break;
+               }
+       }
+       if (error)
+               fifo_close(vp, mode, cred, p);
+       return (error);
+}
+
+/*
+ * Vnode op for read
+ */
+/* ARGSUSED */
+fifo_read(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       register struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+       register struct socket *rso = vp->v_fifoinfo->fi_readsock;
+       int error, startresid;
+
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_READ)
+               panic("fifo_read mode");
+#endif
+       if (uio->uio_resid == 0)
+               return (0);
+       if (ioflag & IO_NDELAY)
+               rso->so_state |= SS_NBIO;
+       startresid = uio->uio_resid;
+       VOP_UNLOCK(vp);
+       error = soreceive(rso, (struct mbuf **)0, uio, (int *)0,
+               (struct mbuf **)0, (struct mbuf **)0);
+       VOP_LOCK(vp);
+       /*
+        * Clear EOF indication after first such return.
+        */
+       if (uio->uio_resid == startresid)
+               rso->so_state &= ~SS_CANTRCVMORE;
+       if (ioflag & IO_NDELAY)
+               rso->so_state &= ~SS_NBIO;
+       return (error);
+}
+
+/*
+ * Vnode op for write
+ */
+/* ARGSUSED */
+fifo_write(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       register struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+       struct socket *wso = vp->v_fifoinfo->fi_writesock;
+       int error;
+
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_WRITE)
+               panic("fifo_write mode");
+#endif
+       if (ioflag & IO_NDELAY)
+               wso->so_state |= SS_NBIO;
+       VOP_UNLOCK(vp);
+       error = sosend(wso, (struct mbuf *)0, uio, 0, (struct mbuf *)0);
+       VOP_LOCK(vp);
+       if (ioflag & IO_NDELAY)
+               wso->so_state &= ~SS_NBIO;
+       return (error);
+}
+
+/*
+ * Device ioctl operation.
+ */
+/* ARGSUSED */
+fifo_ioctl(vp, com, data, fflag, cred, p)
+       struct vnode *vp;
+       int com;
+       caddr_t data;
+       int fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+       struct file filetmp;
+       int error;
+
+       if (com == FIONBIO)
+               return (0);
+       if (fflag & FREAD)
+               filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock;
+       else
+               filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock;
+       return (soo_ioctl(&filetmp, com, data, p));
+}
+
+/* ARGSUSED */
+fifo_select(vp, which, fflag, cred, p)
+       struct vnode *vp;
+       int which, fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+       struct file filetmp;
+       int error;
+
+       if (fflag & FREAD)
+               filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock;
+       else
+               filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock;
+       return (soo_select(&filetmp, which, p));
+}
+
+/*
+ * This is a noop, simply returning what one has been given.
+ */
+fifo_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+
+       if (vpp != NULL)
+               *vpp = vp;
+       if (bnp != NULL)
+               *bnp = bn;
+       return (0);
+}
+
+/*
+ * At the moment we do not do any locking.
+ */
+/* ARGSUSED */
+fifo_lock(vp)
+       struct vnode *vp;
+{
+
+       return (0);
+}
+
+/* ARGSUSED */
+fifo_unlock(vp)
+       struct vnode *vp;
+{
+
+       return (0);
+}
+
+/*
+ * Device close routine
+ */
+/* ARGSUSED */
+fifo_close(vp, fflag, cred, p)
+       register struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+       register struct fifoinfo *fip = vp->v_fifoinfo;
+       int error1, error2;
+
+       if (fflag & FWRITE) {
+               fip->fi_writers--;
+               if (fip->fi_writers == 0)
+                       socantrcvmore(fip->fi_readsock);
+       } else {
+               fip->fi_readers--;
+               if (fip->fi_readers == 0)
+                       socantsendmore(fip->fi_writesock);
+       }
+       if (vp->v_usecount > 1)
+               return (0);
+       error1 = soclose(fip->fi_readsock);
+       error2 = soclose(fip->fi_writesock);
+       FREE(fip, M_VNODE);
+       vp->v_fifoinfo = NULL;
+       if (error1)
+               return (error1);
+       return (error2);
+}
+
+/*
+ * Print out the contents of a fifo vnode.
+ */
+fifo_print(vp)
+       struct vnode *vp;
+{
+
+       printf("tag VT_NON");
+       fifo_printinfo(vp);
+       printf("\n");
+}
+
+/*
+ * Print out internal contents of a fifo vnode.
+ */
+fifo_printinfo(vp)
+       struct vnode *vp;
+{
+       register struct fifoinfo *fip = vp->v_fifoinfo;
+
+       printf(", fifo with %d readers and %d writers",
+               fip->fi_readers, fip->fi_writers);
+}
+
+/*
+ * Fifo failed operation
+ */
+fifo_ebadf()
+{
+
+       return (EBADF);
+}
+
+/*
+ * Fifo advisory byte-level locks.
+ */
+/* ARGSUSED */
+fifo_advlock(vp, id, op, fl, flags)
+       struct vnode *vp;
+       caddr_t id;
+       int op;
+       struct flock *fl;
+       int flags;
+{
+
+       return (EOPNOTSUPP);
+}
+
+/*
+ * Fifo bad operation
+ */
+fifo_badop()
+{
+
+       panic("fifo_badop called");
+       /* NOTREACHED */
+}
diff --git a/usr/src/sys.386bsd/kern/init_sysent.c b/usr/src/sys.386bsd/kern/init_sysent.c
new file mode 100644 (file)
index 0000000..92fdcb7
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * System call switch table.
+ *
+ * DO NOT EDIT-- this file is automatically generated.
+ * created from        @(#)syscalls.master     7.26 (Berkeley) 3/25/91
+ */
+
+#include "param.h"
+#include "systm.h"
+
+int    nosys();
+
+int    rexit();
+int    fork();
+int    read();
+int    write();
+int    open();
+int    close();
+int    wait4();
+int    link();
+int    unlink();
+int    chdir();
+int    fchdir();
+int    mknod();
+int    chmod();
+int    chown();
+int    obreak();
+int    getfsstat();
+int    lseek();
+int    getpid();
+int    mount();
+int    unmount();
+int    setuid();
+int    getuid();
+int    geteuid();
+int    ptrace();
+int    recvmsg();
+int    sendmsg();
+int    recvfrom();
+int    accept();
+int    getpeername();
+int    getsockname();
+int    saccess();
+int    chflags();
+int    fchflags();
+int    sync();
+int    kill();
+int    stat();
+int    getppid();
+int    lstat();
+int    dup();
+int    pipe();
+int    getegid();
+int    profil();
+#ifdef KTRACE
+int    ktrace();
+#else
+#endif
+int    sigaction();
+int    getgid();
+int    sigprocmask();
+int    getlogin();
+int    setlogin();
+int    sysacct();
+int    sigpending();
+#ifdef notyet
+int    sigaltstack();
+#else
+#endif
+int    ioctl();
+int    reboot();
+int    revoke();
+int    symlink();
+int    readlink();
+int    execve();
+int    umask();
+int    chroot();
+int    fstat();
+int    getkerninfo();
+int    getpagesize();
+int    msync();
+int    vfork();
+int    sbrk();
+int    sstk();
+int    smmap();
+int    ovadvise();
+int    munmap();
+int    mprotect();
+int    madvise();
+int    mincore();
+int    getgroups();
+int    setgroups();
+int    getpgrp();
+int    setpgid();
+int    setitimer();
+int    swapon();
+int    getitimer();
+int    gethostname();
+int    sethostname();
+int    getdtablesize();
+int    dup2();
+int    fcntl();
+int    select();
+int    fsync();
+int    setpriority();
+int    socket();
+int    connect();
+int    getpriority();
+int    sigreturn();
+int    bind();
+int    setsockopt();
+int    listen();
+int    sigsuspend();
+int    sigstack();
+#ifdef TRACE
+int    vtrace();
+#else
+#endif
+int    gettimeofday();
+int    getrusage();
+int    getsockopt();
+#ifdef vax
+int    resuba();
+#else
+#endif
+int    readv();
+int    writev();
+int    settimeofday();
+int    fchown();
+int    fchmod();
+int    rename();
+int    truncate();
+int    ftruncate();
+int    flock();
+int    mkfifo();
+int    sendto();
+int    shutdown();
+int    socketpair();
+int    mkdir();
+int    rmdir();
+int    utimes();
+int    adjtime();
+int    gethostid();
+int    sethostid();
+int    getrlimit();
+int    setrlimit();
+int    setsid();
+int    quotactl();
+#ifdef NFS
+int    nfssvc();
+#else
+#endif
+int    getdirentries();
+int    statfs();
+int    fstatfs();
+#ifdef NFS
+int    async_daemon();
+int    getfh();
+#else
+#endif
+#ifdef SYSVSHM
+int    shmsys();
+#else
+#endif
+int    setgid();
+int    setegid();
+int    seteuid();
+
+#ifdef COMPAT_43
+#define compat(n, name) n, __CONCAT(o,name)
+
+int    ocreat();
+#ifdef KTRACE
+#else
+#endif
+#ifdef notyet
+#else
+#endif
+int    owait();
+int    oaccept();
+int    osend();
+int    orecv();
+int    osigvec();
+int    osigblock();
+int    osigsetmask();
+int    orecvmsg();
+int    osendmsg();
+#ifdef TRACE
+#else
+#endif
+#ifdef vax
+#else
+#endif
+int    orecvfrom();
+int    osetreuid();
+int    osetregid();
+int    ogetpeername();
+int    okillpg();
+int    oquota();
+int    ogetsockname();
+#ifdef NFS
+#else
+#endif
+#ifdef NFS
+#else
+#endif
+#ifdef SYSVSHM
+#else
+#endif
+
+#else /* COMPAT_43 */
+#define compat(n, name) 0, nosys
+#endif /* COMPAT_43 */
+
+struct sysent sysent[] = {
+       0, nosys,                       /* 0 = indir or out-of-range */
+       1, rexit,                       /* 1 = exit */
+       0, fork,                        /* 2 = fork */
+       3, read,                        /* 3 = read */
+       3, write,                       /* 4 = write */
+       3, open,                        /* 5 = open */
+       1, close,                       /* 6 = close */
+       4, wait4,                       /* 7 = wait4 */
+       compat(2,creat),                /* 8 = old creat */
+       2, link,                        /* 9 = link */
+       1, unlink,                      /* 10 = unlink */
+       0, nosys,                       /* 11 = obsolete execv */
+       1, chdir,                       /* 12 = chdir */
+       1, fchdir,                      /* 13 = fchdir */
+       3, mknod,                       /* 14 = mknod */
+       2, chmod,                       /* 15 = chmod */
+       3, chown,                       /* 16 = chown */
+       1, obreak,                      /* 17 = break */
+       3, getfsstat,                   /* 18 = getfsstat */
+       3, lseek,                       /* 19 = lseek */
+       0, getpid,                      /* 20 = getpid */
+       4, mount,                       /* 21 = mount */
+       2, unmount,                     /* 22 = unmount */
+       1, setuid,                      /* 23 = setuid */
+       0, getuid,                      /* 24 = getuid */
+       0, geteuid,                     /* 25 = geteuid */
+       4, ptrace,                      /* 26 = ptrace */
+       3, recvmsg,                     /* 27 = recvmsg */
+       3, sendmsg,                     /* 28 = sendmsg */
+       6, recvfrom,                    /* 29 = recvfrom */
+       3, accept,                      /* 30 = accept */
+       3, getpeername,                 /* 31 = getpeername */
+       3, getsockname,                 /* 32 = getsockname */
+       2, saccess,                     /* 33 = access */
+       2, chflags,                     /* 34 = chflags */
+       2, fchflags,                    /* 35 = fchflags */
+       0, sync,                        /* 36 = sync */
+       2, kill,                        /* 37 = kill */
+       2, stat,                        /* 38 = stat */
+       0, getppid,                     /* 39 = getppid */
+       2, lstat,                       /* 40 = lstat */
+       2, dup,                 /* 41 = dup */
+       0, pipe,                        /* 42 = pipe */
+       0, getegid,                     /* 43 = getegid */
+       4, profil,                      /* 44 = profil */
+#ifdef KTRACE
+       4, ktrace,                      /* 45 = ktrace */
+#else
+       0, nosys,                       /* 45 = ktrace */
+#endif
+       3, sigaction,                   /* 46 = sigaction */
+       0, getgid,                      /* 47 = getgid */
+       2, sigprocmask,                 /* 48 = sigprocmask */
+       2, getlogin,                    /* 49 = getlogin */
+       1, setlogin,                    /* 50 = setlogin */
+       1, sysacct,                     /* 51 = acct */
+       0, sigpending,                  /* 52 = sigpending */
+#ifdef notyet
+       3, sigaltstack,                 /* 53 = sigaltstack */
+#else
+       0, nosys,                       /* 53 = sigaltstack */
+#endif
+       3, ioctl,                       /* 54 = ioctl */
+       1, reboot,                      /* 55 = reboot */
+       1, revoke,                      /* 56 = revoke */
+       2, symlink,                     /* 57 = symlink */
+       3, readlink,                    /* 58 = readlink */
+       3, execve,                      /* 59 = execve */
+       1, umask,                       /* 60 = umask */
+       1, chroot,                      /* 61 = chroot */
+       2, fstat,                       /* 62 = fstat */
+       4, getkerninfo,                 /* 63 = getkerninfo */
+       0, getpagesize,                 /* 64 = getpagesize */
+       2, msync,                       /* 65 = msync */
+       0, vfork,                       /* 66 = vfork */
+       0, nosys,                       /* 67 = obsolete vread */
+       0, nosys,                       /* 68 = obsolete vwrite */
+       1, sbrk,                        /* 69 = sbrk */
+       1, sstk,                        /* 70 = sstk */
+       6, smmap,                       /* 71 = mmap */
+       1, ovadvise,                    /* 72 = vadvise */
+       2, munmap,                      /* 73 = munmap */
+       3, mprotect,                    /* 74 = mprotect */
+       3, madvise,                     /* 75 = madvise */
+       0, nosys,                       /* 76 = obsolete vhangup */
+       0, nosys,                       /* 77 = obsolete vlimit */
+       3, mincore,                     /* 78 = mincore */
+       2, getgroups,                   /* 79 = getgroups */
+       2, setgroups,                   /* 80 = setgroups */
+       1, getpgrp,                     /* 81 = getpgrp */
+       2, setpgid,                     /* 82 = setpgid */
+       3, setitimer,                   /* 83 = setitimer */
+       compat(0,wait),         /* 84 = old wait */
+       1, swapon,                      /* 85 = swapon */
+       2, getitimer,                   /* 86 = getitimer */
+       2, gethostname,                 /* 87 = gethostname */
+       2, sethostname,                 /* 88 = sethostname */
+       0, getdtablesize,                       /* 89 = getdtablesize */
+       2, dup2,                        /* 90 = dup2 */
+       0, nosys,                       /* 91 = getdopt */
+       3, fcntl,                       /* 92 = fcntl */
+       5, select,                      /* 93 = select */
+       0, nosys,                       /* 94 = setdopt */
+       1, fsync,                       /* 95 = fsync */
+       3, setpriority,                 /* 96 = setpriority */
+       3, socket,                      /* 97 = socket */
+       3, connect,                     /* 98 = connect */
+       compat(3,accept),               /* 99 = old accept */
+       2, getpriority,                 /* 100 = getpriority */
+       compat(4,send),         /* 101 = old send */
+       compat(4,recv),         /* 102 = old recv */
+       1, sigreturn,                   /* 103 = sigreturn */
+       3, bind,                        /* 104 = bind */
+       5, setsockopt,                  /* 105 = setsockopt */
+       2, listen,                      /* 106 = listen */
+       0, nosys,                       /* 107 = obsolete vtimes */
+       compat(3,sigvec),               /* 108 = old sigvec */
+       compat(1,sigblock),             /* 109 = old sigblock */
+       compat(1,sigsetmask),           /* 110 = old sigsetmask */
+       1, sigsuspend,                  /* 111 = sigsuspend */
+       2, sigstack,                    /* 112 = sigstack */
+       compat(3,recvmsg),              /* 113 = old recvmsg */
+       compat(3,sendmsg),              /* 114 = old sendmsg */
+#ifdef TRACE
+       2, vtrace,                      /* 115 = vtrace */
+#else
+       0, nosys,                       /* 115 = obsolete vtrace */
+#endif
+       2, gettimeofday,                        /* 116 = gettimeofday */
+       2, getrusage,                   /* 117 = getrusage */
+       5, getsockopt,                  /* 118 = getsockopt */
+#ifdef vax
+       1, resuba,                      /* 119 = resuba */
+#else
+       0, nosys,                       /* 119 = nosys */
+#endif
+       3, readv,                       /* 120 = readv */
+       3, writev,                      /* 121 = writev */
+       2, settimeofday,                        /* 122 = settimeofday */
+       3, fchown,                      /* 123 = fchown */
+       2, fchmod,                      /* 124 = fchmod */
+       compat(6,recvfrom),             /* 125 = old recvfrom */
+       compat(2,setreuid),             /* 126 = old setreuid */
+       compat(2,setregid),             /* 127 = old setregid */
+       2, rename,                      /* 128 = rename */
+       2, truncate,                    /* 129 = truncate */
+       2, ftruncate,                   /* 130 = ftruncate */
+       2, flock,                       /* 131 = flock */
+       2, mkfifo,                      /* 132 = mkfifo */
+       6, sendto,                      /* 133 = sendto */
+       2, shutdown,                    /* 134 = shutdown */
+       5, socketpair,                  /* 135 = socketpair */
+       2, mkdir,                       /* 136 = mkdir */
+       1, rmdir,                       /* 137 = rmdir */
+       2, utimes,                      /* 138 = utimes */
+       0, nosys,                       /* 139 = obsolete 4.2 sigreturn */
+       2, adjtime,                     /* 140 = adjtime */
+       compat(3,getpeername),          /* 141 = old getpeername */
+       0, gethostid,                   /* 142 = gethostid */
+       1, sethostid,                   /* 143 = sethostid */
+       2, getrlimit,                   /* 144 = getrlimit */
+       2, setrlimit,                   /* 145 = setrlimit */
+       compat(2,killpg),               /* 146 = old killpg */
+       0, setsid,                      /* 147 = setsid */
+       4, quotactl,                    /* 148 = quotactl */
+       compat(4,quota),                /* 149 = old quota */
+       compat(3,getsockname),          /* 150 = old getsockname */
+       0, nosys,                       /* 151 = nosys */
+       0, nosys,                       /* 152 = nosys */
+       0, nosys,                       /* 153 = nosys */
+       0, nosys,                       /* 154 = nosys */
+#ifdef NFS
+       5, nfssvc,                      /* 155 = nfssvc */
+#else
+       0, nosys,                       /* 155 = nosys */
+#endif
+       4, getdirentries,                       /* 156 = getdirentries */
+       2, statfs,                      /* 157 = statfs */
+       2, fstatfs,                     /* 158 = fstatfs */
+       0, nosys,                       /* 159 = nosys */
+#ifdef NFS
+       0, async_daemon,                        /* 160 = async_daemon */
+       2, getfh,                       /* 161 = getfh */
+#else
+       0, nosys,                       /* 160 = nosys */
+       0, nosys,                       /* 161 = nosys */
+#endif
+       0, nosys,                       /* 162 = nosys */
+       0, nosys,                       /* 163 = nosys */
+       0, nosys,                       /* 164 = nosys */
+       0, nosys,                       /* 165 = nosys */
+       0, nosys,                       /* 166 = nosys */
+       0, nosys,                       /* 167 = nosys */
+       0, nosys,                       /* 168 = nosys */
+       0, nosys,                       /* 169 = nosys */
+       0, nosys,                       /* 170 = nosys */
+#ifdef SYSVSHM
+       4, shmsys,                      /* 171 = shmsys */
+#else
+       0, nosys,                       /* 171 = nosys */
+#endif
+       0, nosys,                       /* 172 = nosys */
+       0, nosys,                       /* 173 = nosys */
+       0, nosys,                       /* 174 = nosys */
+       0, nosys,                       /* 175 = nosys */
+       0, nosys,                       /* 176 = nosys */
+       0, nosys,                       /* 177 = nosys */
+       0, nosys,                       /* 178 = nosys */
+       0, nosys,                       /* 179 = nosys */
+       0, nosys,                       /* 180 = nosys */
+       1, setgid,                      /* 181 = setgid */
+       1, setegid,                     /* 182 = setegid */
+       1, seteuid,                     /* 183 = seteuid */
+       0, nosys,                       /* 184 = nosys */
+       0, nosys,                       /* 185 = nosys */
+       0, nosys,                       /* 186 = nosys */
+       0, nosys,                       /* 187 = nosys */
+       0, nosys,                       /* 188 = nosys */
+       0, nosys,                       /* 189 = nosys */
+       0, nosys,                       /* 190 = nosys */
+};
+
+int    nsysent = sizeof(sysent) / sizeof(sysent[0]);
diff --git a/usr/src/sys.386bsd/kern/kern_acct.c b/usr/src/sys.386bsd/kern/kern_acct.c
new file mode 100644 (file)
index 0000000..c1e07cf
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: @(#)kern_acct.c   7.18 (Berkeley) 5/11/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "namei.h"
+#include "resourcevar.h"
+#include "proc.h"
+#include "ioctl.h"
+#include "termios.h"
+#include "tty.h"
+#include "vnode.h"
+#include "mount.h"
+#include "kernel.h"
+#include "file.h"
+#include "acct.h"
+#include "syslog.h"
+
+/*
+ * Values associated with enabling and disabling accounting
+ */
+int    acctsuspend = 2;        /* stop accounting when < 2% free space left */
+int    acctresume = 4;         /* resume when free space risen to > 4% */
+struct timeval chk = { 15, 0 };/* frequency to check space for accounting */
+struct  vnode *acctp;          /* file to which to do accounting */
+struct  vnode *savacctp;       /* file to which to do accounting when space */
+
+/*
+ * Enable or disable process accounting.
+ *
+ * If a non-null filename is given, that file is used to store accounting
+ * records on process exit. If a null filename is given process accounting
+ * is suspended. If accounting is enabled, the system checks the amount
+ * of freespace on the filesystem at timeval intervals. If the amount of
+ * freespace is below acctsuspend percent, accounting is suspended. If
+ * accounting has been suspended, and freespace rises above acctresume,
+ * accounting is resumed.
+ */
+/* ARGSUSED */
+sysacct(p, uap, retval)
+       struct proc *p;
+       struct args {
+               char    *fname;
+       } *uap;
+       int *retval;
+{
+
+       /*
+        * Body deleted.
+        */
+       return (ENOSYS);
+}
+
+/*
+ * Periodically check the file system to see if accounting
+ * should be turned on or off.
+ */
+acctwatch(resettime)
+       struct timeval *resettime;
+{
+       struct statfs sb;
+
+       if (savacctp) {
+               (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
+               if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
+                       acctp = savacctp;
+                       savacctp = NULL;
+                       log(LOG_NOTICE, "Accounting resumed\n");
+                       return;
+               }
+       }
+       if (acctp == NULL)
+               return;
+       (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
+       if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
+               savacctp = acctp;
+               acctp = NULL;
+               log(LOG_NOTICE, "Accounting suspended\n");
+       }
+       timeout(acctwatch, (caddr_t)resettime, hzto(resettime));
+}
+
+/*
+ * This routine calculates an accounting record for a process and,
+ * if accounting is enabled, writes it to the accounting file.
+ */
+acct(p)
+       register struct proc *p;
+{
+
+       /*
+        * Body deleted.
+        */
+       return;
+}
diff --git a/usr/src/sys.386bsd/kern/kern_kinfo.c b/usr/src/sys.386bsd/kern/kern_kinfo.c
new file mode 100644 (file)
index 0000000..f97eff2
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kern_kinfo.c        7.17 (Berkeley) 6/26/91
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "kinfo.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "buf.h"
+#include "file.h"
+
+#include "vm/vm.h"
+
+#include "kinfo_proc.h"
+
+#define snderr(e) { error = (e); goto release;}
+extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file();
+struct kinfo_lock kinfo_lock;
+
+/* ARGSUSED */
+getkerninfo(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     op;
+               char    *where;
+               int     *size;
+               int     arg;
+       } *uap;
+       int *retval;
+{
+
+       int bufsize;            /* max size of users buffer */
+       int needed, locked, (*server)(), error = 0;
+
+       if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
+           sizeof (bufsize)))
+               goto done;
+
+       switch (ki_type(uap->op)) {
+
+       case KINFO_PROC:
+               server = kinfo_doproc;
+               break;
+
+       case KINFO_RT:
+               server = kinfo_rtable;
+               break;
+
+       case KINFO_VNODE:
+               server = kinfo_vnode;
+               break;
+
+       case KINFO_FILE:
+               server = kinfo_file;
+               break;
+
+       default:
+               error = EINVAL;
+               goto done;
+       }
+       if (uap->where == NULL || uap->size == NULL) {
+               error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
+               goto done;
+       }
+       while (kinfo_lock.kl_lock) {
+               kinfo_lock.kl_want++;
+               sleep(&kinfo_lock, PRIBIO+1);
+               kinfo_lock.kl_want--;
+               kinfo_lock.kl_locked++;
+       }
+       kinfo_lock.kl_lock++;
+
+       if (!useracc(uap->where, bufsize, B_WRITE))
+               snderr(EFAULT);
+       if (server != kinfo_vnode)      /* XXX */
+               vslock(uap->where, bufsize);
+       locked = bufsize;
+       error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
+       if (server != kinfo_vnode)      /* XXX */
+               vsunlock(uap->where, locked, B_WRITE);
+       if (error == 0)
+               error = copyout((caddr_t)&bufsize,
+                               (caddr_t)uap->size, sizeof (bufsize));
+release:
+       kinfo_lock.kl_lock--;
+       if (kinfo_lock.kl_want)
+               wakeup(&kinfo_lock);
+done:
+       if (!error)
+               *retval = needed;
+       return (error);
+}
+
+/* 
+ * try over estimating by 5 procs 
+ */
+#define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc))
+
+kinfo_doproc(op, where, acopysize, arg, aneeded)
+       char *where;
+       int *acopysize, *aneeded;
+{
+       register struct proc *p;
+       register struct kinfo_proc *dp = (struct kinfo_proc *)where;
+       register needed = 0;
+       int buflen;
+       int doingzomb;
+       struct eproc eproc;
+       int error = 0;
+
+       if (where != NULL)
+               buflen = *acopysize;
+
+       p = allproc;
+       doingzomb = 0;
+again:
+       for (; p != NULL; p = p->p_nxt) {
+               /* 
+                * TODO - make more efficient (see notes below).
+                * do by session. 
+                */
+               switch (ki_op(op)) {
+
+               case KINFO_PROC_PID:
+                       /* could do this with just a lookup */
+                       if (p->p_pid != (pid_t)arg)
+                               continue;
+                       break;
+
+               case KINFO_PROC_PGRP:
+                       /* could do this by traversing pgrp */
+                       if (p->p_pgrp->pg_id != (pid_t)arg)
+                               continue;
+                       break;
+
+               case KINFO_PROC_TTY:
+                       if ((p->p_flag&SCTTY) == 0 || 
+                           p->p_session->s_ttyp == NULL ||
+                           p->p_session->s_ttyp->t_dev != (dev_t)arg)
+                               continue;
+                       break;
+
+               case KINFO_PROC_UID:
+                       if (p->p_ucred->cr_uid != (uid_t)arg)
+                               continue;
+                       break;
+
+               case KINFO_PROC_RUID:
+                       if (p->p_cred->p_ruid != (uid_t)arg)
+                               continue;
+                       break;
+               }
+               if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
+                       fill_eproc(p, &eproc);
+                       if (error = copyout((caddr_t)p, &dp->kp_proc, 
+                           sizeof (struct proc)))
+                               return (error);
+                       if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 
+                           sizeof (eproc)))
+                               return (error);
+                       dp++;
+                       buflen -= sizeof (struct kinfo_proc);
+               }
+               needed += sizeof (struct kinfo_proc);
+       }
+       if (doingzomb == 0) {
+               p = zombproc;
+               doingzomb++;
+               goto again;
+       }
+       if (where != NULL)
+               *acopysize = (caddr_t)dp - where;
+       else
+               needed += KINFO_PROCSLOP;
+       *aneeded = needed;
+
+       return (0);
+}
+
+/*
+ * Fill in an eproc structure for the specified process.
+ */
+void
+fill_eproc(p, ep)
+       register struct proc *p;
+       register struct eproc *ep;
+{
+       register struct tty *tp;
+
+       ep->e_paddr = p;
+       ep->e_sess = p->p_pgrp->pg_session;
+       ep->e_pcred = *p->p_cred;
+       ep->e_ucred = *p->p_ucred;
+       ep->e_vm = *p->p_vmspace;
+       if (p->p_pptr)
+               ep->e_ppid = p->p_pptr->p_pid;
+       else
+               ep->e_ppid = 0;
+       ep->e_pgid = p->p_pgrp->pg_id;
+       ep->e_jobc = p->p_pgrp->pg_jobc;
+       if ((p->p_flag&SCTTY) && 
+            (tp = ep->e_sess->s_ttyp)) {
+               ep->e_tdev = tp->t_dev;
+               ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
+               ep->e_tsess = tp->t_session;
+       } else
+               ep->e_tdev = NODEV;
+       ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
+       if (SESS_LEADER(p))
+               ep->e_flag |= EPROC_SLEADER;
+       if (p->p_wmesg)
+               strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
+       ep->e_xsize = ep->e_xrssize = 0;
+       ep->e_xccount = ep->e_xswrss = 0;
+}
+
+/*
+ * Get file structures.
+ */
+kinfo_file(op, where, acopysize, arg, aneeded)
+       register char *where;
+       int *acopysize, *aneeded;
+{
+       int buflen, needed, error;
+       struct file *fp;
+       char *start = where;
+
+       if (where == NULL) {
+               /*
+                * overestimate by 10 files
+                */
+               *aneeded = sizeof (filehead) + 
+                       (nfiles + 10) * sizeof (struct file);
+               return (0);
+       }
+       buflen = *acopysize;
+       needed = 0;
+
+       /*
+        * first copyout filehead
+        */
+       if (buflen > sizeof (filehead)) {
+               if (error = copyout((caddr_t)&filehead, where,
+                   sizeof (filehead)))
+                       return (error);
+               buflen -= sizeof (filehead);
+               where += sizeof (filehead);
+       }
+       needed += sizeof (filehead);
+
+       /*
+        * followed by an array of file structures
+        */
+       for (fp = filehead; fp != NULL; fp = fp->f_filef) {
+               if (buflen > sizeof (struct file)) {
+                       if (error = copyout((caddr_t)fp, where,
+                           sizeof (struct file)))
+                               return (error);
+                       buflen -= sizeof (struct file);
+                       where += sizeof (struct file);
+               }
+               needed += sizeof (struct file);
+       }
+       *acopysize = where - start;
+       *aneeded = needed;
+
+       return (0);
+}
diff --git a/usr/src/sys.386bsd/kern/kern_ktrace.c b/usr/src/sys.386bsd/kern/kern_ktrace.c
new file mode 100644 (file)
index 0000000..dcde2c1
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kern_ktrace.c       7.15 (Berkeley) 6/21/91
+ */
+
+#ifdef KTRACE
+
+#include "param.h"
+#include "proc.h"
+#include "file.h"
+#include "namei.h"
+#include "vnode.h"
+#include "ktrace.h"
+#include "malloc.h"
+#include "syslog.h"
+
+struct ktr_header *
+ktrgetheader(type)
+{
+       register struct ktr_header *kth;
+       struct proc *p = curproc;       /* XXX */
+
+       MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 
+               M_TEMP, M_WAITOK);
+       kth->ktr_type = type;
+       microtime(&kth->ktr_time);
+       kth->ktr_pid = p->p_pid;
+       bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
+       return (kth);
+}
+
+ktrsyscall(vp, code, narg, args)
+       struct vnode *vp;
+       int code, narg, args[];
+{
+       struct  ktr_header *kth = ktrgetheader(KTR_SYSCALL);
+       struct  ktr_syscall *ktp;
+       register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
+       int     *argp, i;
+
+       MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
+       ktp->ktr_code = code;
+       ktp->ktr_narg = narg;
+       argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
+       for (i = 0; i < narg; i++)
+               *argp++ = args[i];
+       kth->ktr_buf = (caddr_t)ktp;
+       kth->ktr_len = len;
+       ktrwrite(vp, kth);
+       FREE(ktp, M_TEMP);
+       FREE(kth, M_TEMP);
+}
+
+ktrsysret(vp, code, error, retval)
+       struct vnode *vp;
+       int code, error, retval;
+{
+       struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
+       struct ktr_sysret ktp;
+
+       ktp.ktr_code = code;
+       ktp.ktr_error = error;
+       ktp.ktr_retval = retval;                /* what about val2 ? */
+
+       kth->ktr_buf = (caddr_t)&ktp;
+       kth->ktr_len = sizeof(struct ktr_sysret);
+
+       ktrwrite(vp, kth);
+       FREE(kth, M_TEMP);
+}
+
+ktrnamei(vp, path)
+       struct vnode *vp;
+       char *path;
+{
+       struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
+
+       kth->ktr_len = strlen(path);
+       kth->ktr_buf = path;
+
+       ktrwrite(vp, kth);
+       FREE(kth, M_TEMP);
+}
+
+ktrgenio(vp, fd, rw, iov, len, error)
+       struct vnode *vp;
+       int fd;
+       enum uio_rw rw;
+       register struct iovec *iov;
+{
+       struct ktr_header *kth = ktrgetheader(KTR_GENIO);
+       register struct ktr_genio *ktp;
+       register caddr_t cp;
+       register int resid = len, cnt;
+       
+       if (error)
+               return;
+       MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
+               M_TEMP, M_WAITOK);
+       ktp->ktr_fd = fd;
+       ktp->ktr_rw = rw;
+       cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
+       while (resid > 0) {
+               if ((cnt = iov->iov_len) > resid)
+                       cnt = resid;
+               if (copyin(iov->iov_base, cp, (unsigned)cnt))
+                       goto done;
+               cp += cnt;
+               resid -= cnt;
+               iov++;
+       }
+       kth->ktr_buf = (caddr_t)ktp;
+       kth->ktr_len = sizeof (struct ktr_genio) + len;
+
+       ktrwrite(vp, kth);
+done:
+       FREE(kth, M_TEMP);
+       FREE(ktp, M_TEMP);
+}
+
+ktrpsig(vp, sig, action, mask, code)
+       struct  vnode *vp;
+       sig_t   action;
+{
+       struct ktr_header *kth = ktrgetheader(KTR_PSIG);
+       struct ktr_psig kp;
+
+       kp.signo = (char)sig;
+       kp.action = action;
+       kp.mask = mask;
+       kp.code = code;
+       kth->ktr_buf = (caddr_t)&kp;
+       kth->ktr_len = sizeof (struct ktr_psig);
+
+       ktrwrite(vp, kth);
+       FREE(kth, M_TEMP);
+}
+
+/* Interface and common routines */
+
+/*
+ * ktrace system call
+ */
+/* ARGSUSED */
+ktrace(curp, uap, retval)
+       struct proc *curp;
+       register struct args {
+               char    *fname;
+               int     ops;
+               int     facs;
+               int     pid;
+       } *uap;
+       int *retval;
+{
+       register struct vnode *vp = NULL;
+       register struct proc *p;
+       struct pgrp *pg;
+       int facs = uap->facs & ~KTRFAC_ROOT;
+       int ops = KTROP(uap->ops);
+       int descend = uap->ops & KTRFLAG_DESCEND;
+       int ret = 0;
+       int error = 0;
+       struct nameidata nd;
+
+       if (ops != KTROP_CLEAR) {
+               /*
+                * an operation which requires a file argument.
+                */
+               nd.ni_segflg = UIO_USERSPACE;
+               nd.ni_dirp = uap->fname;
+               if (error = vn_open(&nd, curp, FREAD|FWRITE, 0))
+                       return (error);
+               vp = nd.ni_vp;
+               VOP_UNLOCK(vp);
+               if (vp->v_type != VREG) {
+                       (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
+                       return (EACCES);
+               }
+       }
+       /*
+        * Clear all uses of the tracefile
+        */
+       if (ops == KTROP_CLEARFILE) {
+               for (p = allproc; p != NULL; p = p->p_nxt) {
+                       if (p->p_tracep == vp) {
+                               if (ktrcanset(curp, p)) {
+                                       p->p_tracep = NULL;
+                                       p->p_traceflag = 0;
+                                       (void) vn_close(vp, FREAD|FWRITE,
+                                               p->p_ucred, p);
+                               } else
+                                       error = EPERM;
+                       }
+               }
+               goto done;
+       }
+       /*
+        * need something to (un)trace (XXX - why is this here?)
+        */
+       if (!facs) {
+               error = EINVAL;
+               goto done;
+       }
+       /* 
+        * do it
+        */
+       if (uap->pid < 0) {
+               /*
+                * by process group
+                */
+               pg = pgfind(-uap->pid);
+               if (pg == NULL) {
+                       error = ESRCH;
+                       goto done;
+               }
+               for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
+                       if (descend)
+                               ret |= ktrsetchildren(curp, p, ops, facs, vp);
+                       else 
+                               ret |= ktrops(curp, p, ops, facs, vp);
+                                       
+       } else {
+               /*
+                * by pid
+                */
+               p = pfind(uap->pid);
+               if (p == NULL) {
+                       error = ESRCH;
+                       goto done;
+               }
+               if (descend)
+                       ret |= ktrsetchildren(curp, p, ops, facs, vp);
+               else
+                       ret |= ktrops(curp, p, ops, facs, vp);
+       }
+       if (!ret)
+               error = EPERM;
+done:
+       if (vp != NULL)
+               (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
+       return (error);
+}
+
+ktrops(curp, p, ops, facs, vp)
+       struct proc *curp, *p;
+       struct vnode *vp;
+{
+
+       if (!ktrcanset(curp, p))
+               return (0);
+       if (ops == KTROP_SET) {
+               if (p->p_tracep != vp) { 
+                       /*
+                        * if trace file already in use, relinquish
+                        */
+                       if (p->p_tracep != NULL)
+                               vrele(p->p_tracep);
+                       VREF(vp);
+                       p->p_tracep = vp;
+               }
+               p->p_traceflag |= facs;
+               if (curp->p_ucred->cr_uid == 0)
+                       p->p_traceflag |= KTRFAC_ROOT;
+       } else {        
+               /* KTROP_CLEAR */
+               if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
+                       /* no more tracing */
+                       p->p_traceflag = 0;
+                       if (p->p_tracep != NULL) {
+                               vrele(p->p_tracep);
+                               p->p_tracep = NULL;
+                       }
+               }
+       }
+
+       return (1);
+}
+
+ktrsetchildren(curp, top, ops, facs, vp)
+       struct proc *curp, *top;
+       struct vnode *vp;
+{
+       register struct proc *p;
+       register int ret = 0;
+
+       p = top;
+       for (;;) {
+               ret |= ktrops(curp, p, ops, facs, vp);
+               /*
+                * If this process has children, descend to them next,
+                * otherwise do any siblings, and if done with this level,
+                * follow back up the tree (but not past top).
+                */
+               if (p->p_cptr)
+                       p = p->p_cptr;
+               else if (p == top)
+                       return (ret);
+               else if (p->p_osptr)
+                       p = p->p_osptr;
+               else for (;;) {
+                       p = p->p_pptr;
+                       if (p == top)
+                               return (ret);
+                       if (p->p_osptr) {
+                               p = p->p_osptr;
+                               break;
+                       }
+               }
+       }
+       /*NOTREACHED*/
+}
+
+ktrwrite(vp, kth)
+       struct vnode *vp;
+       register struct ktr_header *kth;
+{
+       struct uio auio;
+       struct iovec aiov[2];
+       register struct proc *p = curproc;      /* XXX */
+       int error;
+
+       if (vp == NULL)
+               return;
+       auio.uio_iov = &aiov[0];
+       auio.uio_offset = 0;
+       auio.uio_segflg = UIO_SYSSPACE;
+       auio.uio_rw = UIO_WRITE;
+       aiov[0].iov_base = (caddr_t)kth;
+       aiov[0].iov_len = sizeof(struct ktr_header);
+       auio.uio_resid = sizeof(struct ktr_header);
+       auio.uio_iovcnt = 1;
+       auio.uio_procp = (struct proc *)0;
+       if (kth->ktr_len > 0) {
+               auio.uio_iovcnt++;
+               aiov[1].iov_base = kth->ktr_buf;
+               aiov[1].iov_len = kth->ktr_len;
+               auio.uio_resid += kth->ktr_len;
+       }
+       VOP_LOCK(vp);
+       error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
+       VOP_UNLOCK(vp);
+       if (!error)
+               return;
+       /*
+        * If error encountered, give up tracing on this vnode.
+        */
+       log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
+           error);
+       for (p = allproc; p != NULL; p = p->p_nxt) {
+               if (p->p_tracep == vp) {
+                       p->p_tracep = NULL;
+                       p->p_traceflag = 0;
+                       vrele(vp);
+               }
+       }
+}
+
+/*
+ * Return true if caller has permission to set the ktracing state
+ * of target.  Essentially, the target can't possess any
+ * more permissions than the caller.  KTRFAC_ROOT signifies that
+ * root previously set the tracing status on the target process, and 
+ * so, only root may further change it.
+ *
+ * TODO: check groups.  use caller effective gid.
+ */
+ktrcanset(callp, targetp)
+       struct proc *callp, *targetp;
+{
+       register struct pcred *caller = callp->p_cred;
+       register struct pcred *target = targetp->p_cred;
+
+       if ((caller->pc_ucred->cr_uid == target->p_ruid &&
+            target->p_ruid == target->p_svuid &&
+            caller->p_rgid == target->p_rgid &&        /* XXX */
+            target->p_rgid == target->p_svgid &&
+            (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
+            caller->pc_ucred->cr_uid == 0)
+               return (1);
+
+       return (0);
+}
+
+#endif
diff --git a/usr/src/sys.386bsd/kern/kern_time.c b/usr/src/sys.386bsd/kern/kern_time.c
new file mode 100644 (file)
index 0000000..e5291f2
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kern_time.c 7.15 (Berkeley) 3/17/91
+ */
+
+#include "param.h"
+#include "resourcevar.h"
+#include "kernel.h"
+#include "proc.h"
+
+#include "machine/cpu.h"
+
+/* 
+ * Time of day and interval timer support.
+ *
+ * These routines provide the kernel entry points to get and set
+ * the time-of-day and per-process interval timers.  Subroutines
+ * here provide support for adding and subtracting timeval structures
+ * and decrementing interval timers, optionally reloading the interval
+ * timers when they expire.
+ */
+
+/* ARGSUSED */
+gettimeofday(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               struct  timeval *tp;
+               struct  timezone *tzp;
+       } *uap;
+       int *retval;
+{
+       struct timeval atv;
+       int error = 0;
+
+       if (uap->tp) {
+               microtime(&atv);
+               if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
+                   sizeof (atv)))
+                       return (error);
+       }
+       if (uap->tzp)
+               error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
+                   sizeof (tz));
+       return (error);
+}
+
+/* ARGSUSED */
+settimeofday(p, uap, retval)
+       struct proc *p;
+       struct args {
+               struct  timeval *tv;
+               struct  timezone *tzp;
+       } *uap;
+       int *retval;
+{
+       struct timeval atv;
+       struct timezone atz;
+       int error, s;
+
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       if (uap->tv) {
+               if (error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
+                   sizeof (struct timeval)))
+                       return (error);
+               /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
+               boottime.tv_sec += atv.tv_sec - time.tv_sec;
+               s = splhigh(); time = atv; splx(s);
+               resettodr();
+       }
+       if (uap->tzp && (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
+           sizeof (atz))) == 0)
+               tz = atz;
+       return (error);
+}
+
+extern int tickadj;                    /* "standard" clock skew, us./tick */
+int    tickdelta;                      /* current clock skew, us. per tick */
+long   timedelta;                      /* unapplied time correction, us. */
+long   bigadj = 1000000;               /* use 10x skew above bigadj us. */
+
+/* ARGSUSED */
+adjtime(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               struct timeval *delta;
+               struct timeval *olddelta;
+       } *uap;
+       int *retval;
+{
+       struct timeval atv, oatv;
+       register long ndelta;
+       int s, error;
+
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       if (error =
+           copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof (struct timeval)))
+               return (error);
+       ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
+       if (timedelta == 0)
+               if (ndelta > bigadj)
+                       tickdelta = 10 * tickadj;
+               else
+                       tickdelta = tickadj;
+       if (ndelta % tickdelta)
+               ndelta = ndelta / tickadj * tickadj;
+
+       s = splclock();
+       if (uap->olddelta) {
+               oatv.tv_sec = timedelta / 1000000;
+               oatv.tv_usec = timedelta % 1000000;
+       }
+       timedelta = ndelta;
+       splx(s);
+
+       if (uap->olddelta)
+               (void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta,
+                       sizeof (struct timeval));
+       return (0);
+}
+
+/*
+ * Get value of an interval timer.  The process virtual and
+ * profiling virtual time timers are kept in the p_stats area, since
+ * they can be swapped out.  These are kept internally in the
+ * way they are specified externally: in time until they expire.
+ *
+ * The real time interval timer is kept in the process table slot
+ * for the process, and its value (it_value) is kept as an
+ * absolute time rather than as a delta, so that it is easy to keep
+ * periodic real-time signals from drifting.
+ *
+ * Virtual time timers are processed in the hardclock() routine of
+ * kern_clock.c.  The real time timer is processed by a timeout
+ * routine, called from the softclock() routine.  Since a callout
+ * may be delayed in real time due to interrupt processing in the system,
+ * it is possible for the real time timeout routine (realitexpire, given below),
+ * to be delayed in real time past when it is supposed to occur.  It
+ * does not suffice, therefore, to reload the real timer .it_value from the
+ * real time timers .it_interval.  Rather, we compute the next time in
+ * absolute time the timer should go off.
+ */
+/* ARGSUSED */
+getitimer(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               u_int   which;
+               struct  itimerval *itv;
+       } *uap;
+       int *retval;
+{
+       struct itimerval aitv;
+       int s;
+
+       if (uap->which > ITIMER_PROF)
+               return (EINVAL);
+       s = splclock();
+       if (uap->which == ITIMER_REAL) {
+               /*
+                * Convert from absoulte to relative time in .it_value
+                * part of real time timer.  If time for real time timer
+                * has passed return 0, else return difference between
+                * current time and time for the timer to go off.
+                */
+               aitv = p->p_realtimer;
+               if (timerisset(&aitv.it_value))
+                       if (timercmp(&aitv.it_value, &time, <))
+                               timerclear(&aitv.it_value);
+                       else
+                               timevalsub(&aitv.it_value, &time);
+       } else
+               aitv = p->p_stats->p_timer[uap->which];
+       splx(s);
+       return (copyout((caddr_t)&aitv, (caddr_t)uap->itv,
+           sizeof (struct itimerval)));
+}
+
+/* ARGSUSED */
+setitimer(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               u_int   which;
+               struct  itimerval *itv, *oitv;
+       } *uap;
+       int *retval;
+{
+       struct itimerval aitv;
+       register struct itimerval *itvp;
+       int s, error;
+
+       if (uap->which > ITIMER_PROF)
+               return (EINVAL);
+       itvp = uap->itv;
+       if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
+           sizeof(struct itimerval))))
+               return (error);
+       if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval)))
+               return (error);
+       if (itvp == 0)
+               return (0);
+       if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
+               return (EINVAL);
+       s = splclock();
+       if (uap->which == ITIMER_REAL) {
+               untimeout(realitexpire, (caddr_t)p);
+               if (timerisset(&aitv.it_value)) {
+                       timevaladd(&aitv.it_value, &time);
+                       timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
+               }
+               p->p_realtimer = aitv;
+       } else
+               p->p_stats->p_timer[uap->which] = aitv;
+       splx(s);
+       return (0);
+}
+
+/*
+ * Real interval timer expired:
+ * send process whose timer expired an alarm signal.
+ * If time is not set up to reload, then just return.
+ * Else compute next time timer should go off which is > current time.
+ * This is where delay in processing this timeout causes multiple
+ * SIGALRM calls to be compressed into one.
+ */
+realitexpire(p)
+       register struct proc *p;
+{
+       int s;
+
+       psignal(p, SIGALRM);
+       if (!timerisset(&p->p_realtimer.it_interval)) {
+               timerclear(&p->p_realtimer.it_value);
+               return;
+       }
+       for (;;) {
+               s = splclock();
+               timevaladd(&p->p_realtimer.it_value,
+                   &p->p_realtimer.it_interval);
+               if (timercmp(&p->p_realtimer.it_value, &time, >)) {
+                       timeout(realitexpire, (caddr_t)p,
+                           hzto(&p->p_realtimer.it_value));
+                       splx(s);
+                       return;
+               }
+               splx(s);
+       }
+}
+
+/*
+ * Check that a proposed value to load into the .it_value or
+ * .it_interval part of an interval timer is acceptable, and
+ * fix it to have at least minimal value (i.e. if it is less
+ * than the resolution of the clock, round it up.)
+ */
+itimerfix(tv)
+       struct timeval *tv;
+{
+
+       if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
+           tv->tv_usec < 0 || tv->tv_usec >= 1000000)
+               return (EINVAL);
+       if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
+               tv->tv_usec = tick;
+       return (0);
+}
+
+/*
+ * Decrement an interval timer by a specified number
+ * of microseconds, which must be less than a second,
+ * i.e. < 1000000.  If the timer expires, then reload
+ * it.  In this case, carry over (usec - old value) to
+ * reducint the value reloaded into the timer so that
+ * the timer does not drift.  This routine assumes
+ * that it is called in a context where the timers
+ * on which it is operating cannot change in value.
+ */
+itimerdecr(itp, usec)
+       register struct itimerval *itp;
+       int usec;
+{
+
+       if (itp->it_value.tv_usec < usec) {
+               if (itp->it_value.tv_sec == 0) {
+                       /* expired, and already in next interval */
+                       usec -= itp->it_value.tv_usec;
+                       goto expire;
+               }
+               itp->it_value.tv_usec += 1000000;
+               itp->it_value.tv_sec--;
+       }
+       itp->it_value.tv_usec -= usec;
+       usec = 0;
+       if (timerisset(&itp->it_value))
+               return (1);
+       /* expired, exactly at end of interval */
+expire:
+       if (timerisset(&itp->it_interval)) {
+               itp->it_value = itp->it_interval;
+               itp->it_value.tv_usec -= usec;
+               if (itp->it_value.tv_usec < 0) {
+                       itp->it_value.tv_usec += 1000000;
+                       itp->it_value.tv_sec--;
+               }
+       } else
+               itp->it_value.tv_usec = 0;              /* sec is already 0 */
+       return (0);
+}
+
+/*
+ * Add and subtract routines for timevals.
+ * N.B.: subtract routine doesn't deal with
+ * results which are before the beginning,
+ * it just gets very confused in this case.
+ * Caveat emptor.
+ */
+timevaladd(t1, t2)
+       struct timeval *t1, *t2;
+{
+
+       t1->tv_sec += t2->tv_sec;
+       t1->tv_usec += t2->tv_usec;
+       timevalfix(t1);
+}
+
+timevalsub(t1, t2)
+       struct timeval *t1, *t2;
+{
+
+       t1->tv_sec -= t2->tv_sec;
+       t1->tv_usec -= t2->tv_usec;
+       timevalfix(t1);
+}
+
+timevalfix(t1)
+       struct timeval *t1;
+{
+
+       if (t1->tv_usec < 0) {
+               t1->tv_sec--;
+               t1->tv_usec += 1000000;
+       }
+       if (t1->tv_usec >= 1000000) {
+               t1->tv_sec++;
+               t1->tv_usec -= 1000000;
+       }
+}
diff --git a/usr/src/sys.386bsd/kern/kern_xxx.c b/usr/src/sys.386bsd/kern/kern_xxx.c
new file mode 100644 (file)
index 0000000..ab93812
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kern_xxx.c  7.17 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "proc.h"
+#include "reboot.h"
+
+/* ARGSUSED */
+gethostid(p, uap, retval)
+       struct proc *p;
+       void *uap;
+       long *retval;
+{
+
+       *retval = hostid;
+       return (0);
+}
+
+/* ARGSUSED */
+sethostid(p, uap, retval)
+       struct proc *p;
+       struct args {
+               long    hostid;
+       } *uap;
+       int *retval;
+{
+       int error;
+
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       hostid = uap->hostid;
+       return (0);
+}
+
+/* ARGSUSED */
+gethostname(p, uap, retval)
+       struct proc *p;
+       struct args {
+               char    *hostname;
+               u_int   len;
+       } *uap;
+       int *retval;
+{
+
+       if (uap->len > hostnamelen + 1)
+               uap->len = hostnamelen + 1;
+       return (copyout((caddr_t)hostname, (caddr_t)uap->hostname, uap->len));
+}
+
+/* ARGSUSED */
+sethostname(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               char    *hostname;
+               u_int   len;
+       } *uap;
+       int *retval;
+{
+       int error;
+
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       if (uap->len > sizeof (hostname) - 1)
+               return (EINVAL);
+       hostnamelen = uap->len;
+       error = copyin((caddr_t)uap->hostname, hostname, uap->len);
+       hostname[hostnamelen] = 0;
+       return (error);
+}
+
+/* ARGSUSED */
+reboot(p, uap, retval)
+       struct proc *p;
+       struct args {
+               int     opt;
+       } *uap;
+       int *retval;
+{
+       int error;
+
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       boot(uap->opt);
+       return (0);
+}
+
+#ifdef COMPAT_43
+oquota()
+{
+
+       return (ENOSYS);
+}
+#endif
diff --git a/usr/src/sys.386bsd/kern/subr_xxx.c b/usr/src/sys.386bsd/kern/subr_xxx.c
new file mode 100644 (file)
index 0000000..4d8ce97
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)subr_xxx.c  7.10 (Berkeley) 4/20/91
+ */
+
+/*
+ * Miscellaneous trivial functions, including many
+ * that are often inline-expanded or done in assembler.
+ */
+#include "param.h"
+#include "systm.h"
+#include "machine/cpu.h"
+
+/*
+ * Unsupported device function (e.g. writing to read-only device).
+ */
+enodev()
+{
+
+       return (ENODEV);
+}
+
+/*
+ * Unconfigured device function; driver not configured.
+ */
+enxio()
+{
+
+       return (ENXIO);
+}
+
+/*
+ * Unsupported ioctl function.
+ */
+enoioctl()
+{
+
+       return (ENOTTY);
+}
+
+/*
+ * Unsupported system function.
+ * This is used for an otherwise-reasonable operation
+ * that is not supported by the current system binary.
+ */
+enosys()
+{
+
+       return (ENOSYS);
+}
+
+/*
+ * Return error for operation not supported
+ * on a specific object or file type.
+ */
+eopnotsupp()
+{
+
+       return (EOPNOTSUPP);
+}
+
+/*
+ * Generic null operation, always returns success.
+ */
+nullop()
+{
+
+       return (0);
+}
+
+/*
+ * Definitions of various trivial functions;
+ * usually expanded inline rather than being defined here.
+ */
+#ifdef NEED_MINMAX
+imin(a, b)
+       int a, b;
+{
+
+       return (a < b ? a : b);
+}
+
+imax(a, b)
+       int a, b;
+{
+
+       return (a > b ? a : b);
+}
+
+unsigned int
+min(a, b)
+       unsigned int a, b;
+{
+
+       return (a < b ? a : b);
+}
+
+unsigned int
+max(a, b)
+       unsigned int a, b;
+{
+
+       return (a > b ? a : b);
+}
+
+long
+lmin(a, b)
+       long a, b;
+{
+
+       return (a < b ? a : b);
+}
+
+long
+lmax(a, b)
+       long a, b;
+{
+
+       return (a > b ? a : b);
+}
+
+unsigned long
+ulmin(a, b)
+       unsigned long a, b;
+{
+
+       return (a < b ? a : b);
+}
+
+unsigned long
+ulmax(a, b)
+       unsigned long a, b;
+{
+
+       return (a > b ? a : b);
+}
+#endif /* NEED_MINMAX */
+
+#ifdef NEED_FFS
+ffs(mask)
+       register long mask;
+{
+       register int bit;
+
+       if (!mask)
+               return(0);
+       for (bit = 1;; ++bit) {
+               if (mask&0x01)
+                       return(bit);
+               mask >>= 1;
+       }
+}
+#endif /* NEED_FFS */
+
+#ifdef NEED_BCMP
+bcmp(v1, v2, len)
+       void *v1, *v2;
+       register unsigned len;
+{
+       register u_char *s1 = v1, *s2 = v2;
+
+       while (len--)
+               if (*s1++ != *s2++)
+                       return (1);
+       return (0);
+}
+#endif /* NEED_BCMP */
+
+#ifdef NEED_STRLEN
+strlen(s1)
+       register char *s1;
+{
+       register int len;
+
+       for (len = 0; *s1++ != '\0'; len++)
+               ;
+       return (len);
+}
+#endif /* NEED_STRLEN */
diff --git a/usr/src/sys.386bsd/kern/sys_generic.c b/usr/src/sys.386bsd/kern/sys_generic.c
new file mode 100644 (file)
index 0000000..1c2dad2
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)sys_generic.c       7.30 (Berkeley) 5/30/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "filedesc.h"
+#include "ioctl.h"
+#include "file.h"
+#include "socketvar.h"
+#include "proc.h"
+#include "uio.h"
+#include "kernel.h"
+#include "stat.h"
+#include "malloc.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+/*
+ * Read system call.
+ */
+/* ARGSUSED */
+read(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     fdes;
+               char    *cbuf;
+               unsigned count;
+       } *uap;
+       int *retval;
+{
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
+       struct uio auio;
+       struct iovec aiov;
+       long cnt, error = 0;
+#ifdef KTRACE
+       struct iovec ktriov;
+#endif
+
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
+           (fp->f_flag & FREAD) == 0)
+               return (EBADF);
+       aiov.iov_base = (caddr_t)uap->cbuf;
+       aiov.iov_len = uap->count;
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       auio.uio_resid = uap->count;
+       auio.uio_rw = UIO_READ;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))
+               ktriov = aiov;
+#endif
+       cnt = uap->count;
+       if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (KTRPOINT(p, KTR_GENIO) && error == 0)
+               ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
+#endif
+       *retval = cnt;
+       return (error);
+}
+
+/*
+ * Scatter read system call.
+ */
+/* ARGSUSED */
+readv(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     fdes;
+               struct  iovec *iovp;
+               unsigned iovcnt;
+       } *uap;
+       int *retval;
+{
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
+       struct uio auio;
+       register struct iovec *iov;
+       struct iovec *saveiov;
+       struct iovec aiov[UIO_SMALLIOV];
+       long i, cnt, error = 0;
+       unsigned iovlen;
+#ifdef KTRACE
+       struct iovec *ktriov = NULL;
+#endif
+
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
+           (fp->f_flag & FREAD) == 0)
+               return (EBADF);
+       /* note: can't use iovlen until iovcnt is validated */
+       iovlen = uap->iovcnt * sizeof (struct iovec);
+       if (uap->iovcnt > UIO_SMALLIOV) {
+               if (uap->iovcnt > UIO_MAXIOV)
+                       return (EINVAL);
+               MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
+               saveiov = iov;
+       } else
+               iov = aiov;
+       auio.uio_iov = iov;
+       auio.uio_iovcnt = uap->iovcnt;
+       auio.uio_rw = UIO_READ;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+       if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
+               goto done;
+       auio.uio_resid = 0;
+       for (i = 0; i < uap->iovcnt; i++) {
+               if (iov->iov_len < 0) {
+                       error = EINVAL;
+                       goto done;
+               }
+               auio.uio_resid += iov->iov_len;
+               if (auio.uio_resid < 0) {
+                       error = EINVAL;
+                       goto done;
+               }
+               iov++;
+       }
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))  {
+               MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
+               bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
+       }
+#endif
+       cnt = auio.uio_resid;
+       if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (ktriov != NULL) {
+               if (error == 0)
+                       ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
+                           cnt, error);
+               FREE(ktriov, M_TEMP);
+       }
+#endif
+       *retval = cnt;
+done:
+       if (uap->iovcnt > UIO_SMALLIOV)
+               FREE(saveiov, M_IOV);
+       return (error);
+}
+
+/*
+ * Write system call
+ */
+write(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     fdes;
+               char    *cbuf;
+               unsigned count;
+       } *uap;
+       int *retval;
+{
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
+       struct uio auio;
+       struct iovec aiov;
+       long cnt, error = 0;
+#ifdef KTRACE
+       struct iovec ktriov;
+#endif
+
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
+           (fp->f_flag & FWRITE) == 0)
+               return (EBADF);
+       aiov.iov_base = (caddr_t)uap->cbuf;
+       aiov.iov_len = uap->count;
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       auio.uio_resid = uap->count;
+       auio.uio_rw = UIO_WRITE;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))
+               ktriov = aiov;
+#endif
+       cnt = uap->count;
+       if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+               if (error == EPIPE)
+                       psignal(p, SIGPIPE);
+       }
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (KTRPOINT(p, KTR_GENIO) && error == 0)
+               ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
+                   &ktriov, cnt, error);
+#endif
+       *retval = cnt;
+       return (error);
+}
+
+/*
+ * Gather write system call
+ */
+writev(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     fdes;
+               struct  iovec *iovp;
+               unsigned iovcnt;
+       } *uap;
+       int *retval;
+{
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
+       struct uio auio;
+       register struct iovec *iov;
+       struct iovec *saveiov;
+       struct iovec aiov[UIO_SMALLIOV];
+       long i, cnt, error = 0;
+       unsigned iovlen;
+#ifdef KTRACE
+       struct iovec *ktriov = NULL;
+#endif
+
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
+           (fp->f_flag & FWRITE) == 0)
+               return (EBADF);
+       /* note: can't use iovlen until iovcnt is validated */
+       iovlen = uap->iovcnt * sizeof (struct iovec);
+       if (uap->iovcnt > UIO_SMALLIOV) {
+               if (uap->iovcnt > UIO_MAXIOV)
+                       return (EINVAL);
+               MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
+               saveiov = iov;
+       } else
+               iov = aiov;
+       auio.uio_iov = iov;
+       auio.uio_iovcnt = uap->iovcnt;
+       auio.uio_rw = UIO_WRITE;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+       if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
+               goto done;
+       auio.uio_resid = 0;
+       for (i = 0; i < uap->iovcnt; i++) {
+               if (iov->iov_len < 0) {
+                       error = EINVAL;
+                       goto done;
+               }
+               auio.uio_resid += iov->iov_len;
+               if (auio.uio_resid < 0) {
+                       error = EINVAL;
+                       goto done;
+               }
+               iov++;
+       }
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))  {
+               MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
+               bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
+       }
+#endif
+       cnt = auio.uio_resid;
+       if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+               if (error == EPIPE)
+                       psignal(p, SIGPIPE);
+       }
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (ktriov != NULL) {
+               if (error == 0)
+                       ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
+                               ktriov, cnt, error);
+               FREE(ktriov, M_TEMP);
+       }
+#endif
+       *retval = cnt;
+done:
+       if (uap->iovcnt > UIO_SMALLIOV)
+               FREE(saveiov, M_IOV);
+       return (error);
+}
+
+/*
+ * Ioctl system call
+ */
+/* ARGSUSED */
+ioctl(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     fdes;
+               int     cmd;
+               caddr_t cmarg;
+       } *uap;
+       int *retval;
+{
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
+       register int com, error;
+       register u_int size;
+       caddr_t memp = 0;
+#define STK_PARAMS     128
+       char stkbuf[STK_PARAMS];
+       caddr_t data = stkbuf;
+       int tmp;
+
+       if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
+               return (EBADF);
+       if ((fp->f_flag & (FREAD|FWRITE)) == 0)
+               return (EBADF);
+       com = uap->cmd;
+
+       if (com == FIOCLEX) {
+               fdp->fd_ofileflags[uap->fdes] |= UF_EXCLOSE;
+               return (0);
+       }
+       if (com == FIONCLEX) {
+               fdp->fd_ofileflags[uap->fdes] &= ~UF_EXCLOSE;
+               return (0);
+       }
+
+       /*
+        * Interpret high order word to find
+        * amount of data to be copied to/from the
+        * user's address space.
+        */
+       size = IOCPARM_LEN(com);
+       if (size > IOCPARM_MAX)
+               return (ENOTTY);
+       if (size > sizeof (stkbuf)) {
+               memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
+               data = memp;
+       }
+       if (com&IOC_IN) {
+               if (size) {
+                       error = copyin(uap->cmarg, data, (u_int)size);
+                       if (error) {
+                               if (memp)
+                                       free(memp, M_IOCTLOPS);
+                               return (error);
+                       }
+               } else
+                       *(caddr_t *)data = uap->cmarg;
+       } else if ((com&IOC_OUT) && size)
+               /*
+                * Zero the buffer so the user always
+                * gets back something deterministic.
+                */
+               bzero(data, size);
+       else if (com&IOC_VOID)
+               *(caddr_t *)data = uap->cmarg;
+
+       switch (com) {
+
+       case FIONBIO:
+               if (tmp = *(int *)data)
+                       fp->f_flag |= FNONBLOCK;
+               else
+                       fp->f_flag &= ~FNONBLOCK;
+               error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
+               break;
+
+       case FIOASYNC:
+               if (tmp = *(int *)data)
+                       fp->f_flag |= FASYNC;
+               else
+                       fp->f_flag &= ~FASYNC;
+               error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
+               break;
+
+       case FIOSETOWN:
+               tmp = *(int *)data;
+               if (fp->f_type == DTYPE_SOCKET) {
+                       ((struct socket *)fp->f_data)->so_pgid = tmp;
+                       error = 0;
+                       break;
+               }
+               if (tmp <= 0) {
+                       tmp = -tmp;
+               } else {
+                       struct proc *p1 = pfind(tmp);
+                       if (p1 == 0) {
+                               error = ESRCH;
+                               break;
+                       }
+                       tmp = p1->p_pgrp->pg_id;
+               }
+               error = (*fp->f_ops->fo_ioctl)
+                       (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
+               break;
+
+       case FIOGETOWN:
+               if (fp->f_type == DTYPE_SOCKET) {
+                       error = 0;
+                       *(int *)data = ((struct socket *)fp->f_data)->so_pgid;
+                       break;
+               }
+               error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
+               *(int *)data = -*(int *)data;
+               break;
+
+       default:
+               error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
+               /*
+                * Copy any data to user, size was
+                * already set and checked above.
+                */
+               if (error == 0 && (com&IOC_OUT) && size)
+                       error = copyout(data, uap->cmarg, (u_int)size);
+               break;
+       }
+       if (memp)
+               free(memp, M_IOCTLOPS);
+       return (error);
+}
+
+int    selwait, nselcoll;
+
+/*
+ * Select system call.
+ */
+select(p, uap, retval)
+       register struct proc *p;
+       register struct args {
+               int     nd;
+               fd_set  *in, *ou, *ex;
+               struct  timeval *tv;
+       } *uap;
+       int *retval;
+{
+       fd_set ibits[3], obits[3];
+       struct timeval atv;
+       int s, ncoll, ni, error = 0, timo;
+
+       bzero((caddr_t)ibits, sizeof(ibits));
+       bzero((caddr_t)obits, sizeof(obits));
+       if (uap->nd > p->p_fd->fd_nfiles)
+               uap->nd = p->p_fd->fd_nfiles;   /* forgiving; slightly wrong */
+       ni = howmany(uap->nd, NFDBITS);
+
+#define        getbits(name, x) \
+       if (uap->name) { \
+               error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
+                   (unsigned)(ni * sizeof(fd_mask))); \
+               if (error) \
+                       goto done; \
+       }
+       getbits(in, 0);
+       getbits(ou, 1);
+       getbits(ex, 2);
+#undef getbits
+
+       if (uap->tv) {
+               error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
+                       sizeof (atv));
+               if (error)
+                       goto done;
+               if (itimerfix(&atv)) {
+                       error = EINVAL;
+                       goto done;
+               }
+               s = splhigh(); timevaladd(&atv, &time); splx(s);
+               timo = hzto(&atv);
+       } else
+               timo = 0;
+retry:
+       ncoll = nselcoll;
+       p->p_flag |= SSEL;
+       error = selscan(p, ibits, obits, uap->nd, retval);
+       if (error || *retval)
+               goto done;
+       s = splhigh();
+       /* this should be timercmp(&time, &atv, >=) */
+       if (uap->tv && (time.tv_sec > atv.tv_sec ||
+           time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
+               splx(s);
+               goto done;
+       }
+       if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
+               splx(s);
+               goto retry;
+       }
+       p->p_flag &= ~SSEL;
+       error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
+       splx(s);
+       if (error == 0)
+               goto retry;
+done:
+       p->p_flag &= ~SSEL;
+       /* select is not restarted after signals... */
+       if (error == ERESTART)
+               error = EINTR;
+       if (error == EWOULDBLOCK)
+               error = 0;
+#define        putbits(name, x) \
+       if (uap->name) { \
+               int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
+                   (unsigned)(ni * sizeof(fd_mask))); \
+               if (error2) \
+                       error = error2; \
+       }
+       if (error == 0) {
+               putbits(in, 0);
+               putbits(ou, 1);
+               putbits(ex, 2);
+#undef putbits
+       }
+       return (error);
+}
+
+selscan(p, ibits, obits, nfd, retval)
+       struct proc *p;
+       fd_set *ibits, *obits;
+       int nfd, *retval;
+{
+       register struct filedesc *fdp = p->p_fd;
+       register int which, i, j;
+       register fd_mask bits;
+       int flag;
+       struct file *fp;
+       int error = 0, n = 0;
+
+       for (which = 0; which < 3; which++) {
+               switch (which) {
+
+               case 0:
+                       flag = FREAD; break;
+
+               case 1:
+                       flag = FWRITE; break;
+
+               case 2:
+                       flag = 0; break;
+               }
+               for (i = 0; i < nfd; i += NFDBITS) {
+                       bits = ibits[which].fds_bits[i/NFDBITS];
+                       while ((j = ffs(bits)) && i + --j < nfd) {
+                               bits &= ~(1 << j);
+                               fp = fdp->fd_ofiles[i + j];
+                               if (fp == NULL) {
+                                       error = EBADF;
+                                       break;
+                               }
+                               if ((*fp->f_ops->fo_select)(fp, flag, p)) {
+                                       FD_SET(i + j, &obits[which]);
+                                       n++;
+                               }
+                       }
+               }
+       }
+       *retval = n;
+       return (error);
+}
+
+/*ARGSUSED*/
+#ifdef __STDC__
+seltrue(dev_t dev, int which, struct proc *p)
+#else
+seltrue(dev, flag, p)
+       dev_t dev;
+       int flag;
+       struct proc *p;
+#endif
+{
+
+       return (1);
+}
+
+selwakeup(p, coll)
+       register struct proc *p;
+       int coll;
+{
+
+       if (coll) {
+               nselcoll++;
+               wakeup((caddr_t)&selwait);
+       }
+       if (p) {
+               int s = splhigh();
+               if (p->p_wchan == (caddr_t)&selwait) {
+                       if (p->p_stat == SSLEEP)
+                               setrun(p);
+                       else
+                               unsleep(p);
+               } else if (p->p_flag & SSEL)
+                       p->p_flag &= ~SSEL;
+               splx(s);
+       }
+}
diff --git a/usr/src/sys.386bsd/kern/sys_socket.c b/usr/src/sys.386bsd/kern/sys_socket.c
new file mode 100644 (file)
index 0000000..241a12f
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)sys_socket.c        7.11 (Berkeley) 4/16/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "file.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "ioctl.h"
+#include "stat.h"
+
+#include "net/if.h"
+#include "net/route.h"
+
+struct fileops socketops =
+    { soo_read, soo_write, soo_ioctl, soo_select, soo_close };
+
+/* ARGSUSED */
+soo_read(fp, uio, cred)
+       struct file *fp;
+       struct uio *uio;
+       struct ucred *cred;
+{
+
+       return (soreceive((struct socket *)fp->f_data, (struct mbuf **)0,
+               uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
+}
+
+/* ARGSUSED */
+soo_write(fp, uio, cred)
+       struct file *fp;
+       struct uio *uio;
+       struct ucred *cred;
+{
+
+       return (sosend((struct socket *)fp->f_data, (struct mbuf *)0,
+               uio, (struct mbuf *)0, (struct mbuf *)0, 0));
+}
+
+soo_ioctl(fp, cmd, data, p)
+       struct file *fp;
+       int cmd;
+       register caddr_t data;
+       struct proc *p;
+{
+       register struct socket *so = (struct socket *)fp->f_data;
+
+       switch (cmd) {
+
+       case FIONBIO:
+               if (*(int *)data)
+                       so->so_state |= SS_NBIO;
+               else
+                       so->so_state &= ~SS_NBIO;
+               return (0);
+
+       case FIOASYNC:
+               if (*(int *)data) {
+                       so->so_state |= SS_ASYNC;
+                       so->so_rcv.sb_flags |= SB_ASYNC;
+                       so->so_snd.sb_flags |= SB_ASYNC;
+               } else {
+                       so->so_state &= ~SS_ASYNC;
+                       so->so_rcv.sb_flags &= ~SB_ASYNC;
+                       so->so_snd.sb_flags &= ~SB_ASYNC;
+               }
+               return (0);
+
+       case FIONREAD:
+               *(int *)data = so->so_rcv.sb_cc;
+               return (0);
+
+       case SIOCSPGRP:
+               so->so_pgid = *(int *)data;
+               return (0);
+
+       case SIOCGPGRP:
+               *(int *)data = so->so_pgid;
+               return (0);
+
+       case SIOCATMARK:
+               *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
+               return (0);
+       }
+       /*
+        * Interface/routing/protocol specific ioctls:
+        * interface and routing ioctls should have a
+        * different entry since a socket's unnecessary
+        */
+       if (IOCGROUP(cmd) == 'i')
+               return (ifioctl(so, cmd, data, p));
+       if (IOCGROUP(cmd) == 'r')
+               return (rtioctl(cmd, data, p));
+       return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 
+           (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0));
+}
+
+soo_select(fp, which, p)
+       struct file *fp;
+       int which;
+       struct proc *p;
+{
+       register struct socket *so = (struct socket *)fp->f_data;
+       register int s = splnet();
+
+       switch (which) {
+
+       case FREAD:
+               if (soreadable(so)) {
+                       splx(s);
+                       return (1);
+               }
+               sbselqueue(&so->so_rcv, p);
+               break;
+
+       case FWRITE:
+               if (sowriteable(so)) {
+                       splx(s);
+                       return (1);
+               }
+               sbselqueue(&so->so_snd, p);
+               break;
+
+       case 0:
+               if (so->so_oobmark ||
+                   (so->so_state & SS_RCVATMARK)) {
+                       splx(s);
+                       return (1);
+               }
+               sbselqueue(&so->so_rcv, p);
+               break;
+       }
+       splx(s);
+       return (0);
+}
+
+soo_stat(so, ub)
+       register struct socket *so;
+       register struct stat *ub;
+{
+
+       bzero((caddr_t)ub, sizeof (*ub));
+       return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE,
+           (struct mbuf *)ub, (struct mbuf *)0, 
+           (struct mbuf *)0));
+}
+
+/* ARGSUSED */
+soo_close(fp, p)
+       struct file *fp;
+       struct proc *p;
+{
+       int error = 0;
+
+       if (fp->f_data)
+               error = soclose((struct socket *)fp->f_data);
+       fp->f_data = 0;
+       return (error);
+}
diff --git a/usr/src/sys.386bsd/kern/syscalls.c b/usr/src/sys.386bsd/kern/syscalls.c
new file mode 100644 (file)
index 0000000..2753835
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * System call names.
+ *
+ * DO NOT EDIT-- this file is automatically generated.
+ * created from        @(#)syscalls.master     7.26 (Berkeley) 3/25/91
+ */
+
+char *syscallnames[] = {
+       "#0",                   /* 0 = indir or out-of-range */
+       "exit",                 /* 1 = exit */
+       "fork",                 /* 2 = fork */
+       "read",                 /* 3 = read */
+       "write",                        /* 4 = write */
+       "open",                 /* 5 = open */
+       "close",                        /* 6 = close */
+       "wait4",                        /* 7 = wait4 */
+       "old.creat",            /* 8 = old creat */
+       "link",                 /* 9 = link */
+       "unlink",                       /* 10 = unlink */
+       "obs_execv",                    /* 11 = obsolete execv */
+       "chdir",                        /* 12 = chdir */
+       "fchdir",                       /* 13 = fchdir */
+       "mknod",                        /* 14 = mknod */
+       "chmod",                        /* 15 = chmod */
+       "chown",                        /* 16 = chown */
+       "break",                        /* 17 = break */
+       "getfsstat",                    /* 18 = getfsstat */
+       "lseek",                        /* 19 = lseek */
+       "getpid",                       /* 20 = getpid */
+       "mount",                        /* 21 = mount */
+       "unmount",                      /* 22 = unmount */
+       "setuid",                       /* 23 = setuid */
+       "getuid",                       /* 24 = getuid */
+       "geteuid",                      /* 25 = geteuid */
+       "ptrace",                       /* 26 = ptrace */
+       "recvmsg",                      /* 27 = recvmsg */
+       "sendmsg",                      /* 28 = sendmsg */
+       "recvfrom",                     /* 29 = recvfrom */
+       "accept",                       /* 30 = accept */
+       "getpeername",                  /* 31 = getpeername */
+       "getsockname",                  /* 32 = getsockname */
+       "access",                       /* 33 = access */
+       "chflags",                      /* 34 = chflags */
+       "fchflags",                     /* 35 = fchflags */
+       "sync",                 /* 36 = sync */
+       "kill",                 /* 37 = kill */
+       "stat",                 /* 38 = stat */
+       "getppid",                      /* 39 = getppid */
+       "lstat",                        /* 40 = lstat */
+       "dup",                  /* 41 = dup */
+       "pipe",                 /* 42 = pipe */
+       "getegid",                      /* 43 = getegid */
+       "profil",                       /* 44 = profil */
+#ifdef KTRACE
+       "ktrace",                       /* 45 = ktrace */
+#else
+       "#45",                  /* 45 = ktrace */
+#endif
+       "sigaction",                    /* 46 = sigaction */
+       "getgid",                       /* 47 = getgid */
+       "sigprocmask",                  /* 48 = sigprocmask */
+       "getlogin",                     /* 49 = getlogin */
+       "setlogin",                     /* 50 = setlogin */
+       "acct",                 /* 51 = acct */
+       "sigpending",                   /* 52 = sigpending */
+#ifdef notyet
+       "sigaltstack",                  /* 53 = sigaltstack */
+#else
+       "#53",                  /* 53 = sigaltstack */
+#endif
+       "ioctl",                        /* 54 = ioctl */
+       "reboot",                       /* 55 = reboot */
+       "revoke",                       /* 56 = revoke */
+       "symlink",                      /* 57 = symlink */
+       "readlink",                     /* 58 = readlink */
+       "execve",                       /* 59 = execve */
+       "umask",                        /* 60 = umask */
+       "chroot",                       /* 61 = chroot */
+       "fstat",                        /* 62 = fstat */
+       "getkerninfo",                  /* 63 = getkerninfo */
+       "getpagesize",                  /* 64 = getpagesize */
+       "msync",                        /* 65 = msync */
+       "vfork",                        /* 66 = vfork */
+       "obs_vread",                    /* 67 = obsolete vread */
+       "obs_vwrite",                   /* 68 = obsolete vwrite */
+       "sbrk",                 /* 69 = sbrk */
+       "sstk",                 /* 70 = sstk */
+       "mmap",                 /* 71 = mmap */
+       "vadvise",                      /* 72 = vadvise */
+       "munmap",                       /* 73 = munmap */
+       "mprotect",                     /* 74 = mprotect */
+       "madvise",                      /* 75 = madvise */
+       "obs_vhangup",                  /* 76 = obsolete vhangup */
+       "obs_vlimit",                   /* 77 = obsolete vlimit */
+       "mincore",                      /* 78 = mincore */
+       "getgroups",                    /* 79 = getgroups */
+       "setgroups",                    /* 80 = setgroups */
+       "getpgrp",                      /* 81 = getpgrp */
+       "setpgid",                      /* 82 = setpgid */
+       "setitimer",                    /* 83 = setitimer */
+       "old.wait",             /* 84 = old wait */
+       "swapon",                       /* 85 = swapon */
+       "getitimer",                    /* 86 = getitimer */
+       "gethostname",                  /* 87 = gethostname */
+       "sethostname",                  /* 88 = sethostname */
+       "getdtablesize",                        /* 89 = getdtablesize */
+       "dup2",                 /* 90 = dup2 */
+       "#91",                  /* 91 = getdopt */
+       "fcntl",                        /* 92 = fcntl */
+       "select",                       /* 93 = select */
+       "#94",                  /* 94 = setdopt */
+       "fsync",                        /* 95 = fsync */
+       "setpriority",                  /* 96 = setpriority */
+       "socket",                       /* 97 = socket */
+       "connect",                      /* 98 = connect */
+       "old.accept",           /* 99 = old accept */
+       "getpriority",                  /* 100 = getpriority */
+       "old.send",             /* 101 = old send */
+       "old.recv",             /* 102 = old recv */
+       "sigreturn",                    /* 103 = sigreturn */
+       "bind",                 /* 104 = bind */
+       "setsockopt",                   /* 105 = setsockopt */
+       "listen",                       /* 106 = listen */
+       "obs_vtimes",                   /* 107 = obsolete vtimes */
+       "old.sigvec",           /* 108 = old sigvec */
+       "old.sigblock",         /* 109 = old sigblock */
+       "old.sigsetmask",               /* 110 = old sigsetmask */
+       "sigsuspend",                   /* 111 = sigsuspend */
+       "sigstack",                     /* 112 = sigstack */
+       "old.recvmsg",          /* 113 = old recvmsg */
+       "old.sendmsg",          /* 114 = old sendmsg */
+#ifdef TRACE
+       "vtrace",                       /* 115 = vtrace */
+#else
+       "obs_vtrace",                   /* 115 = obsolete vtrace */
+#endif
+       "gettimeofday",                 /* 116 = gettimeofday */
+       "getrusage",                    /* 117 = getrusage */
+       "getsockopt",                   /* 118 = getsockopt */
+#ifdef vax
+       "resuba",                       /* 119 = resuba */
+#else
+       "#119",                 /* 119 = nosys */
+#endif
+       "readv",                        /* 120 = readv */
+       "writev",                       /* 121 = writev */
+       "settimeofday",                 /* 122 = settimeofday */
+       "fchown",                       /* 123 = fchown */
+       "fchmod",                       /* 124 = fchmod */
+       "old.recvfrom",         /* 125 = old recvfrom */
+       "old.setreuid",         /* 126 = old setreuid */
+       "old.setregid",         /* 127 = old setregid */
+       "rename",                       /* 128 = rename */
+       "truncate",                     /* 129 = truncate */
+       "ftruncate",                    /* 130 = ftruncate */
+       "flock",                        /* 131 = flock */
+       "mkfifo",                       /* 132 = mkfifo */
+       "sendto",                       /* 133 = sendto */
+       "shutdown",                     /* 134 = shutdown */
+       "socketpair",                   /* 135 = socketpair */
+       "mkdir",                        /* 136 = mkdir */
+       "rmdir",                        /* 137 = rmdir */
+       "utimes",                       /* 138 = utimes */
+       "obs_4.2",                      /* 139 = obsolete 4.2 sigreturn */
+       "adjtime",                      /* 140 = adjtime */
+       "old.getpeername",              /* 141 = old getpeername */
+       "gethostid",                    /* 142 = gethostid */
+       "sethostid",                    /* 143 = sethostid */
+       "getrlimit",                    /* 144 = getrlimit */
+       "setrlimit",                    /* 145 = setrlimit */
+       "old.killpg",           /* 146 = old killpg */
+       "setsid",                       /* 147 = setsid */
+       "quotactl",                     /* 148 = quotactl */
+       "old.quota",            /* 149 = old quota */
+       "old.getsockname",              /* 150 = old getsockname */
+       "#151",                 /* 151 = nosys */
+       "#152",                 /* 152 = nosys */
+       "#153",                 /* 153 = nosys */
+       "#154",                 /* 154 = nosys */
+#ifdef NFS
+       "nfssvc",                       /* 155 = nfssvc */
+#else
+       "#155",                 /* 155 = nosys */
+#endif
+       "getdirentries",                        /* 156 = getdirentries */
+       "statfs",                       /* 157 = statfs */
+       "fstatfs",                      /* 158 = fstatfs */
+       "#159",                 /* 159 = nosys */
+#ifdef NFS
+       "async_daemon",                 /* 160 = async_daemon */
+       "getfh",                        /* 161 = getfh */
+#else
+       "#160",                 /* 160 = nosys */
+       "#161",                 /* 161 = nosys */
+#endif
+       "#162",                 /* 162 = nosys */
+       "#163",                 /* 163 = nosys */
+       "#164",                 /* 164 = nosys */
+       "#165",                 /* 165 = nosys */
+       "#166",                 /* 166 = nosys */
+       "#167",                 /* 167 = nosys */
+       "#168",                 /* 168 = nosys */
+       "#169",                 /* 169 = nosys */
+       "#170",                 /* 170 = nosys */
+#ifdef SYSVSHM
+       "shmsys",                       /* 171 = shmsys */
+#else
+       "#171",                 /* 171 = nosys */
+#endif
+       "#172",                 /* 172 = nosys */
+       "#173",                 /* 173 = nosys */
+       "#174",                 /* 174 = nosys */
+       "#175",                 /* 175 = nosys */
+       "#176",                 /* 176 = nosys */
+       "#177",                 /* 177 = nosys */
+       "#178",                 /* 178 = nosys */
+       "#179",                 /* 179 = nosys */
+       "#180",                 /* 180 = nosys */
+       "setgid",                       /* 181 = setgid */
+       "setegid",                      /* 182 = setegid */
+       "seteuid",                      /* 183 = seteuid */
+       "#184",                 /* 184 = nosys */
+       "#185",                 /* 185 = nosys */
+       "#186",                 /* 186 = nosys */
+       "#187",                 /* 187 = nosys */
+       "#188",                 /* 188 = nosys */
+       "#189",                 /* 189 = nosys */
+       "#190",                 /* 190 = nosys */
+};
diff --git a/usr/src/sys.386bsd/kern/sysv_shm.c b/usr/src/sys.386bsd/kern/sysv_shm.c
new file mode 100644 (file)
index 0000000..fca74d3
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department. Originally from University of Wisconsin.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$
+ *
+ *     @(#)sysv_shm.c  7.15 (Berkeley) 5/13/91
+ */
+
+/*
+ * System V shared memory routines.
+ * TEMPORARY, until mmap is in place;
+ * needed now for HP-UX compatibility and X server (yech!).
+ */
+
+#ifdef SYSVSHM
+
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "proc.h"
+#include "shm.h"
+#include "malloc.h"
+#include "mman.h"
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_inherit.h"
+#include "vm/vm_pager.h"
+
+#ifdef HPUXCOMPAT
+#include "hp300/hpux/hpux.h"
+#endif
+
+int    shmat(), shmctl(), shmdt(), shmget();
+int    (*shmcalls[])() = { shmat, shmctl, shmdt, shmget };
+int    shmtot = 0;
+
+/*
+ * Per process internal structure for managing segments.
+ * Each process using shm will have an array of ``shmseg'' of these.
+ */
+struct shmdesc {
+       vm_offset_t     shmd_uva;
+       int             shmd_id;
+};
+
+/*
+ * Per segment internal structure (shm_handle).
+ */
+struct shmhandle {
+       vm_offset_t     shmh_kva;
+       caddr_t         shmh_id;
+};
+
+vm_map_t shm_map;      /* address space for shared memory segments */
+
+shminit()
+{
+       register int i;
+       vm_offset_t whocares1, whocares2;
+
+       shm_map = kmem_suballoc(kernel_map, &whocares1, &whocares2,
+                               shminfo.shmall * NBPG, FALSE);
+       if (shminfo.shmmni > SHMMMNI)
+               shminfo.shmmni = SHMMMNI;
+       for (i = 0; i < shminfo.shmmni; i++) {
+               shmsegs[i].shm_perm.mode = 0;
+               shmsegs[i].shm_perm.seq = 0;
+       }
+}
+
+/*
+ * Entry point for all SHM calls
+ */
+shmsys(p, uap, retval)
+       struct proc *p;
+       struct args {
+               u_int which;
+       } *uap;
+       int *retval;
+{
+
+       if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
+               return (EINVAL);
+       return ((*shmcalls[uap->which])(p, &uap[1], retval));
+}
+
+/*
+ * Get a shared memory segment
+ */
+shmget(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               key_t key;
+               int size;
+               int shmflg;
+       } *uap;
+       int *retval;
+{
+       register struct shmid_ds *shp;
+       register struct ucred *cred = p->p_ucred;
+       register int i;
+       int error, size, rval = 0;
+       register struct shmhandle *shmh;
+
+       /* look up the specified shm_id */
+       if (uap->key != IPC_PRIVATE) {
+               for (i = 0; i < shminfo.shmmni; i++)
+                       if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) &&
+                           shmsegs[i].shm_perm.key == uap->key) {
+                               rval = i;
+                               break;
+                       }
+       } else
+               i = shminfo.shmmni;
+
+       /* create a new shared segment if necessary */
+       if (i == shminfo.shmmni) {
+               if ((uap->shmflg & IPC_CREAT) == 0)
+                       return (ENOENT);
+               if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
+                       return (EINVAL);
+               for (i = 0; i < shminfo.shmmni; i++)
+                       if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) == 0) {
+                               rval = i;
+                               break;
+                       }
+               if (i == shminfo.shmmni)
+                       return (ENOSPC);
+               size = clrnd(btoc(uap->size));
+               if (shmtot + size > shminfo.shmall)
+                       return (ENOMEM);
+               shp = &shmsegs[rval];
+               /*
+                * We need to do a couple of things to ensure consistency
+                * in case we sleep in malloc().  We mark segment as
+                * allocated so that other shmgets() will not allocate it.
+                * We mark it as "destroyed" to insure that shmvalid() is
+                * false making most operations fail (XXX).  We set the key,
+                * so that other shmget()s will fail.
+                */
+               shp->shm_perm.mode = SHM_ALLOC | SHM_DEST;
+               shp->shm_perm.key = uap->key;
+               shmh = (struct shmhandle *)
+                       malloc(sizeof(struct shmhandle), M_SHM, M_WAITOK);
+               shmh->shmh_kva = 0;
+               shmh->shmh_id = (caddr_t)(0xc0000000|rval);     /* XXX */
+               error = vm_mmap(shm_map, &shmh->shmh_kva, ctob(size),
+                               VM_PROT_ALL, MAP_ANON, shmh->shmh_id, 0);
+               if (error) {
+                       free((caddr_t)shmh, M_SHM);
+                       shp->shm_perm.mode = 0;
+                       return(ENOMEM);
+               }
+               shp->shm_handle = (void *) shmh;
+               shmtot += size;
+               shp->shm_perm.cuid = shp->shm_perm.uid = cred->cr_uid;
+               shp->shm_perm.cgid = shp->shm_perm.gid = cred->cr_gid;
+               shp->shm_perm.mode = SHM_ALLOC | (uap->shmflg&0777);
+               shp->shm_segsz = uap->size;
+               shp->shm_cpid = p->p_pid;
+               shp->shm_lpid = shp->shm_nattch = 0;
+               shp->shm_atime = shp->shm_dtime = 0;
+               shp->shm_ctime = time.tv_sec;
+       } else {
+               shp = &shmsegs[rval];
+               /* XXX: probably not the right thing to do */
+               if (shp->shm_perm.mode & SHM_DEST)
+                       return (EBUSY);
+               if (error = ipcaccess(&shp->shm_perm, uap->shmflg&0777, cred))
+                       return (error);
+               if (uap->size && uap->size > shp->shm_segsz)
+                       return (EINVAL);
+               if ((uap->shmflg&IPC_CREAT) && (uap->shmflg&IPC_EXCL))
+                       return (EEXIST);
+       }
+       *retval = shp->shm_perm.seq * SHMMMNI + rval;
+       return (0);
+}
+
+/*
+ * Shared memory control
+ */
+/* ARGSUSED */
+shmctl(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int shmid;
+               int cmd;
+               caddr_t buf;
+       } *uap;
+       int *retval;
+{
+       register struct shmid_ds *shp;
+       register struct ucred *cred = p->p_ucred;
+       struct shmid_ds sbuf;
+       int error;
+
+       if (error = shmvalid(uap->shmid))
+               return (error);
+       shp = &shmsegs[uap->shmid % SHMMMNI];
+       switch (uap->cmd) {
+       case IPC_STAT:
+               if (error = ipcaccess(&shp->shm_perm, IPC_R, cred))
+                       return (error);
+               return (copyout((caddr_t)shp, uap->buf, sizeof(*shp)));
+
+       case IPC_SET:
+               if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
+                   cred->cr_uid != shp->shm_perm.cuid)
+                       return (EPERM);
+               if (error = copyin(uap->buf, (caddr_t)&sbuf, sizeof sbuf))
+                       return (error);
+               shp->shm_perm.uid = sbuf.shm_perm.uid;
+               shp->shm_perm.gid = sbuf.shm_perm.gid;
+               shp->shm_perm.mode = (shp->shm_perm.mode & ~0777)
+                       | (sbuf.shm_perm.mode & 0777);
+               shp->shm_ctime = time.tv_sec;
+               break;
+
+       case IPC_RMID:
+               if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
+                   cred->cr_uid != shp->shm_perm.cuid)
+                       return (EPERM);
+               /* set ctime? */
+               shp->shm_perm.key = IPC_PRIVATE;
+               shp->shm_perm.mode |= SHM_DEST;
+               if (shp->shm_nattch <= 0)
+                       shmfree(shp);
+               break;
+
+#ifdef HPUXCOMPAT
+       case SHM_LOCK:
+       case SHM_UNLOCK:
+               /* don't really do anything, but make them think we did */
+               if ((p->p_flag & SHPUX) == 0)
+                       return (EINVAL);
+               if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
+                   cred->cr_uid != shp->shm_perm.cuid)
+                       return (EPERM);
+               break;
+#endif
+
+       default:
+               return (EINVAL);
+       }
+       return (0);
+}
+
+/*
+ * Attach to shared memory segment.
+ */
+shmat(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     shmid;
+               caddr_t shmaddr;
+               int     shmflg;
+       } *uap;
+       int *retval;
+{
+       register struct shmid_ds *shp;
+       register int size;
+       caddr_t uva;
+       int error;
+       int flags;
+       vm_prot_t prot;
+       struct shmdesc *shmd;
+
+       /*
+        * Allocate descriptors now (before validity check)
+        * in case malloc() blocks.
+        */
+       shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
+       size = shminfo.shmseg * sizeof(struct shmdesc);
+       if (shmd == NULL) {
+               shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK);
+               bzero((caddr_t)shmd, size);
+               p->p_vmspace->vm_shm = (caddr_t)shmd;
+       }
+       if (error = shmvalid(uap->shmid))
+               return (error);
+       shp = &shmsegs[uap->shmid % SHMMMNI];
+       if (shp->shm_handle == NULL)
+               panic("shmat NULL handle");
+       if (error = ipcaccess(&shp->shm_perm,
+           (uap->shmflg&SHM_RDONLY) ? IPC_R : IPC_R|IPC_W, p->p_ucred))
+               return (error);
+       uva = uap->shmaddr;
+       if (uva && ((int)uva & (SHMLBA-1))) {
+               if (uap->shmflg & SHM_RND)
+                       uva = (caddr_t) ((int)uva & ~(SHMLBA-1));
+               else
+                       return (EINVAL);
+       }
+       /*
+        * Make sure user doesn't use more than their fair share
+        */
+       for (size = 0; size < shminfo.shmseg; size++) {
+               if (shmd->shmd_uva == 0)
+                       break;
+               shmd++;
+       }
+       if (size >= shminfo.shmseg)
+               return (EMFILE);
+       size = ctob(clrnd(btoc(shp->shm_segsz)));
+       prot = VM_PROT_READ;
+       if ((uap->shmflg & SHM_RDONLY) == 0)
+               prot |= VM_PROT_WRITE;
+       flags = MAP_ANON|MAP_SHARED;
+       if (uva)
+               flags |= MAP_FIXED;
+       else
+               uva = (caddr_t)0x1000000;       /* XXX */
+       error = vm_mmap(&p->p_vmspace->vm_map, &uva, (vm_size_t)size, prot,
+           flags, ((struct shmhandle *)shp->shm_handle)->shmh_id, 0);
+       if (error)
+               return(error);
+       shmd->shmd_uva = (vm_offset_t)uva;
+       shmd->shmd_id = uap->shmid;
+       /*
+        * Fill in the remaining fields
+        */
+       shp->shm_lpid = p->p_pid;
+       shp->shm_atime = time.tv_sec;
+       shp->shm_nattch++;
+       *retval = (int) uva;
+       return (0);
+}
+
+/*
+ * Detach from shared memory segment.
+ */
+/* ARGSUSED */
+shmdt(p, uap, retval)
+       struct proc *p;
+       struct args {
+               caddr_t shmaddr;
+       } *uap;
+       int *retval;
+{
+       register struct shmdesc *shmd;
+       register int i;
+
+       shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
+       for (i = 0; i < shminfo.shmseg; i++, shmd++)
+               if (shmd->shmd_uva &&
+                   shmd->shmd_uva == (vm_offset_t)uap->shmaddr)
+                       break;
+       if (i == shminfo.shmseg)
+               return(EINVAL);
+       shmufree(p, shmd);
+       shmsegs[shmd->shmd_id % SHMMMNI].shm_lpid = p->p_pid;
+}
+
+shmfork(p1, p2, isvfork)
+       struct proc *p1, *p2;
+       int isvfork;
+{
+       register struct shmdesc *shmd;
+       register int size;
+
+       /*
+        * Copy parents descriptive information
+        */
+       size = shminfo.shmseg * sizeof(struct shmdesc);
+       shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK);
+       bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmd, size);
+       p2->p_vmspace->vm_shm = (caddr_t)shmd;
+       /*
+        * Increment reference counts
+        */
+       for (size = 0; size < shminfo.shmseg; size++, shmd++)
+               if (shmd->shmd_uva)
+                       shmsegs[shmd->shmd_id % SHMMMNI].shm_nattch++;
+}
+
+shmexit(p)
+       struct proc *p;
+{
+       register struct shmdesc *shmd;
+       register int i;
+
+       shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
+       for (i = 0; i < shminfo.shmseg; i++, shmd++)
+               if (shmd->shmd_uva)
+                       shmufree(p, shmd);
+       free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
+       p->p_vmspace->vm_shm = NULL;
+}
+
+shmvalid(id)
+       register int id;
+{
+       register struct shmid_ds *shp;
+
+       if (id < 0 || (id % SHMMMNI) >= shminfo.shmmni)
+               return(EINVAL);
+       shp = &shmsegs[id % SHMMMNI];
+       if (shp->shm_perm.seq == (id / SHMMMNI) &&
+           (shp->shm_perm.mode & (SHM_ALLOC|SHM_DEST)) == SHM_ALLOC)
+               return(0);
+       return(EINVAL);
+}
+
+/*
+ * Free user resources associated with a shared memory segment
+ */
+shmufree(p, shmd)
+       struct proc *p;
+       struct shmdesc *shmd;
+{
+       register struct shmid_ds *shp;
+
+       shp = &shmsegs[shmd->shmd_id % SHMMMNI];
+       (void) vm_deallocate(&p->p_vmspace->vm_map, shmd->shmd_uva,
+                            ctob(clrnd(btoc(shp->shm_segsz))));
+       shmd->shmd_id = 0;
+       shmd->shmd_uva = 0;
+       shp->shm_dtime = time.tv_sec;
+       if (--shp->shm_nattch <= 0 && (shp->shm_perm.mode & SHM_DEST))
+               shmfree(shp);
+}
+
+/*
+ * Deallocate resources associated with a shared memory segment
+ */
+shmfree(shp)
+       register struct shmid_ds *shp;
+{
+
+       if (shp->shm_handle == NULL)
+               panic("shmfree");
+       /*
+        * Lose our lingering object reference by deallocating space
+        * in kernel.  Pager will also be deallocated as a side-effect.
+        */
+       vm_deallocate(shm_map,
+                     ((struct shmhandle *)shp->shm_handle)->shmh_kva,
+                     ctob(clrnd(btoc(shp->shm_segsz))));
+       free((caddr_t)shp->shm_handle, M_SHM);
+       shp->shm_handle = NULL;
+       shmtot -= clrnd(btoc(shp->shm_segsz));
+       shp->shm_perm.mode = 0;
+       /*
+        * Increment the sequence number to ensure that outstanding
+        * shmids for this segment will be invalid in the event that
+        * the segment is reallocated.  Note that shmids must be
+        * positive as decreed by SVID.
+        */
+       shp->shm_perm.seq++;
+       if ((int)(shp->shm_perm.seq * SHMMMNI) < 0)
+               shp->shm_perm.seq = 0;
+}
+
+/*
+ * XXX This routine would be common to all sysV style IPC
+ *     (if the others were implemented).
+ */
+ipcaccess(ipc, mode, cred)
+       register struct ipc_perm *ipc;
+       int mode;
+       register struct ucred *cred;
+{
+       register int m;
+
+       if (cred->cr_uid == 0)
+               return(0);
+       /*
+        * Access check is based on only one of owner, group, public.
+        * If not owner, then check group.
+        * If not a member of the group, then check public access.
+        */
+       mode &= 0700;
+       m = ipc->mode;
+       if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) {
+               m <<= 3;
+               if (!groupmember(ipc->gid, cred) &&
+                   !groupmember(ipc->cgid, cred))
+                       m <<= 3;
+       }
+       if ((mode&m) == mode)
+               return (0);
+       return (EACCES);
+}
+#endif /* SYSVSHM */
diff --git a/usr/src/sys.386bsd/kern/tty_compat.c b/usr/src/sys.386bsd/kern/tty_compat.c
new file mode 100644 (file)
index 0000000..9bfd6cd
--- /dev/null
@@ -0,0 +1,398 @@
+/*-
+ * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tty_compat.c        7.10 (Berkeley) 5/9/91
+ */
+
+/* 
+ * mapping routines for old line discipline (yuck)
+ */
+#ifdef COMPAT_43
+
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "termios.h"
+#include "proc.h"
+#include "file.h"
+#include "conf.h"
+#include "dkstat.h"
+#include "kernel.h"
+#include "syslog.h"
+
+int ttydebug = 0;
+
+static struct speedtab compatspeeds[] = {
+       38400,  15,
+       19200,  14,
+       9600,   13,
+       4800,   12,
+       2400,   11,
+       1800,   10,
+       1200,   9,
+       600,    8,
+       300,    7,
+       200,    6,
+       150,    5,
+       134,    4,
+       110,    3,
+       75,     2,
+       50,     1,
+       0,      0,
+       -1,     -1,
+};
+static int compatspcodes[16] = { 
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
+       1800, 2400, 4800, 9600, 19200, 38400,
+};
+
+/*ARGSUSED*/
+ttcompat(tp, com, data, flag)
+       register struct tty *tp;
+       caddr_t data;
+{
+
+       switch (com) {
+       case TIOCGETP: {
+               register struct sgttyb *sg = (struct sgttyb *)data;
+               register u_char *cc = tp->t_cc;
+               register speed;
+
+               speed = ttspeedtab(tp->t_ospeed, compatspeeds);
+               sg->sg_ospeed = (speed == -1) ? 15 : speed;
+               if (tp->t_ispeed == 0)
+                       sg->sg_ispeed = sg->sg_ospeed;
+               else {
+                       speed = ttspeedtab(tp->t_ispeed, compatspeeds);
+                       sg->sg_ispeed = (speed == -1) ? 15 : speed;
+               }
+               sg->sg_erase = cc[VERASE];
+               sg->sg_kill = cc[VKILL];
+               sg->sg_flags = ttcompatgetflags(tp);
+               break;
+       }
+
+       case TIOCSETP:
+       case TIOCSETN: {
+               register struct sgttyb *sg = (struct sgttyb *)data;
+               struct termios term;
+               int speed;
+
+               term = tp->t_termios;
+               if ((speed = sg->sg_ispeed) > 15 || speed < 0)
+                       term.c_ispeed = speed;
+               else
+                       term.c_ispeed = compatspcodes[speed];
+               if ((speed = sg->sg_ospeed) > 15 || speed < 0)
+                       term.c_ospeed = speed;
+               else
+                       term.c_ospeed = compatspcodes[speed];
+               term.c_cc[VERASE] = sg->sg_erase;
+               term.c_cc[VKILL] = sg->sg_kill;
+               tp->t_flags = tp->t_flags&0xffff0000 | sg->sg_flags&0xffff;
+               ttcompatsetflags(tp, &term);
+               return (ttioctl(tp, com == TIOCSETP ? TIOCSETAF : TIOCSETA, 
+                       &term, flag));
+       }
+
+       case TIOCGETC: {
+               struct tchars *tc = (struct tchars *)data;
+               register u_char *cc = tp->t_cc;
+
+               tc->t_intrc = cc[VINTR];
+               tc->t_quitc = cc[VQUIT];
+               tc->t_startc = cc[VSTART];
+               tc->t_stopc = cc[VSTOP];
+               tc->t_eofc = cc[VEOF];
+               tc->t_brkc = cc[VEOL];
+               break;
+       }
+       case TIOCSETC: {
+               struct tchars *tc = (struct tchars *)data;
+               register u_char *cc = tp->t_cc;
+
+               cc[VINTR] = tc->t_intrc;
+               cc[VQUIT] = tc->t_quitc;
+               cc[VSTART] = tc->t_startc;
+               cc[VSTOP] = tc->t_stopc;
+               cc[VEOF] = tc->t_eofc;
+               cc[VEOL] = tc->t_brkc;
+               if (tc->t_brkc == -1)
+                       cc[VEOL2] = _POSIX_VDISABLE;
+               break;
+       }
+       case TIOCSLTC: {
+               struct ltchars *ltc = (struct ltchars *)data;
+               register u_char *cc = tp->t_cc;
+
+               cc[VSUSP] = ltc->t_suspc;
+               cc[VDSUSP] = ltc->t_dsuspc;
+               cc[VREPRINT] = ltc->t_rprntc;
+               cc[VDISCARD] = ltc->t_flushc;
+               cc[VWERASE] = ltc->t_werasc;
+               cc[VLNEXT] = ltc->t_lnextc;
+               break;
+       }
+       case TIOCGLTC: {
+               struct ltchars *ltc = (struct ltchars *)data;
+               register u_char *cc = tp->t_cc;
+
+               ltc->t_suspc = cc[VSUSP];
+               ltc->t_dsuspc = cc[VDSUSP];
+               ltc->t_rprntc = cc[VREPRINT];
+               ltc->t_flushc = cc[VDISCARD];
+               ltc->t_werasc = cc[VWERASE];
+               ltc->t_lnextc = cc[VLNEXT];
+               break;
+       }
+       case TIOCLBIS:
+       case TIOCLBIC:
+       case TIOCLSET: {
+               struct termios term;
+
+               term = tp->t_termios;
+               if (com == TIOCLSET)
+                       tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16;
+               else {
+                       tp->t_flags = 
+                        (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff);
+                       if (com == TIOCLBIS)
+                               tp->t_flags |= *(int *)data<<16;
+                       else
+                               tp->t_flags &= ~(*(int *)data<<16);
+               }
+               ttcompatsetlflags(tp, &term);
+               return (ttioctl(tp, TIOCSETA, &term, flag));
+       }
+       case TIOCLGET:
+               *(int *)data = ttcompatgetflags(tp)>>16;
+               if (ttydebug)
+                       printf("CLGET: returning %x\n", *(int *)data);
+               break;
+
+       case OTIOCGETD:
+               *(int *)data = tp->t_line ? tp->t_line : 2;
+               break;
+
+       case OTIOCSETD: {
+               int ldisczero = 0;
+
+               return (ttioctl(tp, TIOCSETD, 
+                       *(int *)data == 2 ? (caddr_t)&ldisczero : data, flag));
+           }
+
+       case OTIOCCONS:
+               *(int *)data = 1;
+               return (ttioctl(tp, TIOCCONS, data, flag));
+
+       default:
+               return (-1);
+       }
+       return (0);
+}
+
+ttcompatgetflags(tp)
+       register struct tty *tp;
+{
+       register long iflag = tp->t_iflag;
+       register long lflag = tp->t_lflag;
+       register long oflag = tp->t_oflag;
+       register long cflag = tp->t_cflag;
+       register flags = 0;
+
+       if (iflag&IXOFF)
+               flags |= TANDEM;
+       if (iflag&ICRNL || oflag&ONLCR)
+               flags |= CRMOD;
+       if (cflag&PARENB) {
+               if (iflag&INPCK) {
+                       if (cflag&PARODD)
+                               flags |= ODDP;
+                       else
+                               flags |= EVENP;
+               } else
+                       flags |= EVENP | ODDP;
+       } else {
+               if ((tp->t_flags&LITOUT) && !(oflag&OPOST))
+                       flags |= LITOUT;
+               if (tp->t_flags&PASS8)
+                       flags |= PASS8;
+       }
+       
+       if ((lflag&ICANON) == 0) {      
+               /* fudge */
+               if (iflag&IXON || lflag&ISIG || lflag&IEXTEN || cflag&PARENB)
+                       flags |= CBREAK;
+               else
+                       flags |= RAW;
+       }
+       if (oflag&OXTABS)
+               flags |= XTABS;
+       if (lflag&ECHOE)
+               flags |= CRTERA|CRTBS;
+       if (lflag&ECHOKE)
+               flags |= CRTKIL|CRTBS;
+       if (lflag&ECHOPRT)
+               flags |= PRTERA;
+       if (lflag&ECHOCTL)
+               flags |= CTLECH;
+       if ((iflag&IXANY) == 0)
+               flags |= DECCTQ;
+       flags |= lflag&(ECHO|MDMBUF|TOSTOP|FLUSHO|NOHANG|PENDIN|NOFLSH);
+if (ttydebug)
+       printf("getflags: %x\n", flags);
+       return (flags);
+}
+
+ttcompatsetflags(tp, t)
+       register struct tty *tp;
+       register struct termios *t;
+{
+       register flags = tp->t_flags;
+       register long iflag = t->c_iflag;
+       register long oflag = t->c_oflag;
+       register long lflag = t->c_lflag;
+       register long cflag = t->c_cflag;
+
+       if (flags & RAW) {
+               iflag &= IXOFF;
+               oflag &= ~OPOST;
+               lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN);
+       } else {
+               iflag |= BRKINT|IXON|IMAXBEL;
+               oflag |= OPOST;
+               lflag |= ISIG|IEXTEN|ECHOCTL;   /* XXX was echoctl on ? */
+               if (flags & XTABS)
+                       oflag |= OXTABS;
+               else
+                       oflag &= ~OXTABS;
+               if (flags & CBREAK)
+                       lflag &= ~ICANON;
+               else
+                       lflag |= ICANON;
+               if (flags&CRMOD) {
+                       iflag |= ICRNL;
+                       oflag |= ONLCR;
+               } else {
+                       iflag &= ~ICRNL;
+                       oflag &= ~ONLCR;
+               }
+       }
+       if (flags&ECHO)
+               lflag |= ECHO;
+       else
+               lflag &= ~ECHO;
+               
+       if (flags&(RAW|LITOUT|PASS8)) {
+               cflag &= ~(CSIZE|PARENB);
+               cflag |= CS8;
+               if ((flags&(RAW|PASS8)) == 0)
+                       iflag |= ISTRIP;
+               else
+                       iflag &= ~ISTRIP;
+       } else {
+               cflag &= ~CSIZE;
+               cflag |= CS7|PARENB;
+               iflag |= ISTRIP;
+       }
+       if ((flags&(EVENP|ODDP)) == EVENP) {
+               iflag |= INPCK;
+               cflag &= ~PARODD;
+       } else if ((flags&(EVENP|ODDP)) == ODDP) {
+               iflag |= INPCK;
+               cflag |= PARODD;
+       } else 
+               iflag &= ~INPCK;
+       if (flags&LITOUT)
+               oflag &= ~OPOST;        /* move earlier ? */
+       if (flags&TANDEM)
+               iflag |= IXOFF;
+       else
+               iflag &= ~IXOFF;
+       t->c_iflag = iflag;
+       t->c_oflag = oflag;
+       t->c_lflag = lflag;
+       t->c_cflag = cflag;
+}
+
+ttcompatsetlflags(tp, t)
+       register struct tty *tp;
+       register struct termios *t;
+{
+       register flags = tp->t_flags;
+       register long iflag = t->c_iflag;
+       register long oflag = t->c_oflag;
+       register long lflag = t->c_lflag;
+       register long cflag = t->c_cflag;
+
+       if (flags&CRTERA)
+               lflag |= ECHOE;
+       else
+               lflag &= ~ECHOE;
+       if (flags&CRTKIL)
+               lflag |= ECHOKE;
+       else
+               lflag &= ~ECHOKE;
+       if (flags&PRTERA)
+               lflag |= ECHOPRT;
+       else
+               lflag &= ~ECHOPRT;
+       if (flags&CTLECH)
+               lflag |= ECHOCTL;
+       else
+               lflag &= ~ECHOCTL;
+       if ((flags&DECCTQ) == 0)
+               lflag |= IXANY;
+       else
+               lflag &= ~IXANY;
+       lflag &= ~(MDMBUF|TOSTOP|FLUSHO|NOHANG|PENDIN|NOFLSH);
+       lflag |= flags&(MDMBUF|TOSTOP|FLUSHO|NOHANG|PENDIN|NOFLSH);
+       if (flags&(LITOUT|PASS8)) {
+               iflag &= ~ISTRIP;
+               cflag &= ~(CSIZE|PARENB);
+               cflag |= CS8;
+               if (flags&LITOUT)
+                       oflag &= ~OPOST;
+               if ((flags&(PASS8|RAW)) == 0)
+                       iflag |= ISTRIP;
+       } else if ((flags&RAW) == 0) {
+               cflag &= ~CSIZE;
+               cflag |= CS7|PARENB;
+               oflag |= OPOST;
+       }
+       t->c_iflag = iflag;
+       t->c_oflag = oflag;
+       t->c_lflag = lflag;
+       t->c_cflag = cflag;
+}
+#endif /* COMPAT_43 */
diff --git a/usr/src/sys.386bsd/kern/tty_conf.c b/usr/src/sys.386bsd/kern/tty_conf.c
new file mode 100644 (file)
index 0000000..2745f43
--- /dev/null
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tty_conf.c  7.6 (Berkeley) 5/9/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "conf.h"
+
+int    enodev();
+int    nullop();
+
+int    ttyopen(),ttylclose(),ttread(),ttwrite(),nullioctl(),ttstart();
+int    ttymodem(), nullmodem(), ttyinput();
+
+#include "tb.h"
+#if NTB > 0
+int    tbopen(),tbclose(),tbread(),tbinput(),tbioctl();
+#endif
+
+#include "sl.h"
+#if NSL > 0
+int    slopen(),slclose(),slinput(),sltioctl(),slstart();
+#endif
+
+
+struct linesw linesw[] =
+{
+       ttyopen, ttylclose, ttread, ttwrite, nullioctl,
+       ttyinput, enodev, nullop, ttstart, ttymodem,    /* 0- termios */
+
+       enodev, enodev, enodev, enodev, enodev,         /* 1- defunct */
+       enodev, enodev, enodev, enodev, enodev,
+
+       enodev, enodev, enodev, enodev, enodev,         /* 2- defunct */
+       enodev, enodev, enodev, enodev, enodev,
+#if NTB > 0
+       tbopen, tbclose, tbread, enodev, tbioctl,
+       tbinput, enodev, nullop, ttstart, nullmodem,    /* 3- TABLDISC */
+#else
+       enodev, enodev, enodev, enodev, enodev,
+       enodev, enodev, enodev, enodev, enodev,
+#endif
+#if NSL > 0
+       slopen, slclose, enodev, enodev, sltioctl,
+       slinput, enodev, nullop, slstart, nullmodem,    /* 4- SLIPDISC */
+#else
+       enodev, enodev, enodev, enodev, enodev,
+       enodev, enodev, enodev, enodev, enodev,
+#endif
+};
+
+int    nldisp = sizeof (linesw) / sizeof (linesw[0]);
+
+/*
+ * Do nothing specific version of line
+ * discipline specific ioctl command.
+ */
+/*ARGSUSED*/
+nullioctl(tp, cmd, data, flags)
+       struct tty *tp;
+       char *data;
+       int flags;
+{
+
+#ifdef lint
+       tp = tp; data = data; flags = flags;
+#endif
+       return (-1);
+}
diff --git a/usr/src/sys.386bsd/kern/tty_tb.c b/usr/src/sys.386bsd/kern/tty_tb.c
new file mode 100644 (file)
index 0000000..971dca2
--- /dev/null
@@ -0,0 +1,366 @@
+/*-
+ * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tty_tb.c    7.7 (Berkeley) 5/9/91
+ */
+
+#include "tb.h"
+#if NTB > 0
+
+/*
+ * Line discipline for RS232 tablets;
+ * supplies binary coordinate data.
+ */
+#include "param.h"
+#include "tablet.h"
+#include "tty.h"
+
+/*
+ * Tablet configuration table.
+ */
+struct tbconf {
+       short   tbc_recsize;    /* input record size in bytes */
+       short   tbc_uiosize;    /* size of data record returned user */
+       int     tbc_sync;       /* mask for finding sync byte/bit */
+       int     (*tbc_decode)();/* decoding routine */
+       char    *tbc_run;       /* enter run mode sequence */
+       char    *tbc_point;     /* enter point mode sequence */
+       char    *tbc_stop;      /* stop sequence */
+       char    *tbc_start;     /* start/restart sequence */
+       int     tbc_flags;
+#define        TBF_POL         0x1     /* polhemus hack */
+#define        TBF_INPROX      0x2     /* tablet has proximity info */
+};
+
+static int tbdecode(), gtcodecode(), poldecode();
+static int tblresdecode(), tbhresdecode();
+
+struct tbconf tbconf[TBTYPE] = {
+{ 0 },
+{ 5, sizeof (struct tbpos), 0200, tbdecode, "6", "4" },
+{ 5, sizeof (struct tbpos), 0200, tbdecode, "\1CN", "\1RT", "\2", "\4" },
+{ 8, sizeof (struct gtcopos), 0200, gtcodecode },
+{17, sizeof (struct polpos), 0200, poldecode, 0, 0, "\21", "\5\22\2\23",
+  TBF_POL },
+{ 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CN", "\1PT", "\2", "\4",
+  TBF_INPROX },
+{ 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CN", "\1PT", "\2", "\4",
+  TBF_INPROX },
+{ 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CL\33", "\1PT\33", 0, 0},
+{ 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CL\33", "\1PT\33", 0, 0},
+};
+
+/*
+ * Tablet state
+ */
+struct tb {
+       int     tbflags;                /* mode & type bits */
+#define        TBMAXREC        17      /* max input record size */
+       char    cbuf[TBMAXREC];         /* input buffer */
+       union {
+               struct  tbpos tbpos;
+               struct  gtcopos gtcopos;
+               struct  polpos polpos;
+       } rets;                         /* processed state */
+#define NTBS   16
+} tb[NTBS];
+
+/*
+ * Open as tablet discipline; called on discipline change.
+ */
+/*ARGSUSED*/
+tbopen(dev, tp)
+       dev_t dev;
+       register struct tty *tp;
+{
+       register struct tb *tbp;
+
+       if (tp->t_line == TABLDISC)
+               return (ENODEV);
+       ttywflush(tp);
+       for (tbp = tb; tbp < &tb[NTBS]; tbp++)
+               if (tbp->tbflags == 0)
+                       break;
+       if (tbp >= &tb[NTBS])
+               return (EBUSY);
+       tbp->tbflags = TBTIGER|TBPOINT;         /* default */
+       tp->t_cp = tbp->cbuf;
+       tp->t_inbuf = 0;
+       bzero((caddr_t)&tbp->rets, sizeof (tbp->rets));
+       tp->T_LINEP = (caddr_t)tbp;
+       tp->t_flags |= LITOUT;
+       return (0);
+}
+
+/*
+ * Line discipline change or last device close.
+ */
+tbclose(tp)
+       register struct tty *tp;
+{
+       register int s;
+       int modebits = TBPOINT|TBSTOP;
+
+       tbioctl(tp, BIOSMODE, &modebits, 0);
+       s = spltty();
+       ((struct tb *)tp->T_LINEP)->tbflags = 0;
+       tp->t_cp = 0;
+       tp->t_inbuf = 0;
+       tp->t_rawq.c_cc = 0;            /* clear queues -- paranoid */
+       tp->t_canq.c_cc = 0;
+       tp->t_line = 0;                 /* paranoid: avoid races */
+       splx(s);
+}
+
+/*
+ * Read from a tablet line.
+ * Characters have been buffered in a buffer and decoded.
+ */
+tbread(tp, uio)
+       register struct tty *tp;
+       struct uio *uio;
+{
+       register struct tb *tbp = (struct tb *)tp->T_LINEP;
+       register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE];
+       int ret;
+
+       if ((tp->t_state&TS_CARR_ON) == 0)
+               return (EIO);
+       ret = uiomove(&tbp->rets, tc->tbc_uiosize, uio);
+       if (tc->tbc_flags&TBF_POL)
+               tbp->rets.polpos.p_key = ' ';
+       return (ret);
+}
+
+/*
+ * Low level character input routine.
+ * Stuff the character in the buffer, and decode
+ * if all the chars are there.
+ *
+ * This routine could be expanded in-line in the receiver
+ * interrupt routine to make it run as fast as possible.
+ */
+tbinput(c, tp)
+       register int c;
+       register struct tty *tp;
+{
+       register struct tb *tbp = (struct tb *)tp->T_LINEP;
+       register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE];
+
+       if (tc->tbc_recsize == 0 || tc->tbc_decode == 0)        /* paranoid? */
+               return;
+       /*
+        * Locate sync bit/byte or reset input buffer.
+        */
+       if (c&tc->tbc_sync || tp->t_inbuf == tc->tbc_recsize) {
+               tp->t_cp = tbp->cbuf;
+               tp->t_inbuf = 0;
+       }
+       *tp->t_cp++ = c&0177;
+       /*
+        * Call decode routine only if a full record has been collected.
+        */
+       if (++tp->t_inbuf == tc->tbc_recsize)
+               (*tc->tbc_decode)(tc, tbp->cbuf, &tbp->rets);
+}
+
+/*
+ * Decode GTCO 8 byte format (high res, tilt, and pressure).
+ */
+static
+gtcodecode(tc, cp, tbpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct gtcopos *tbpos;
+{
+
+       tbpos->pressure = *cp >> 2;
+       tbpos->status = (tbpos->pressure > 16) | TBINPROX; /* half way down */
+       tbpos->xpos = (*cp++ & 03) << 14;
+       tbpos->xpos |= *cp++ << 7;
+       tbpos->xpos |= *cp++;
+       tbpos->ypos = (*cp++ & 03) << 14;
+       tbpos->ypos |= *cp++ << 7;
+       tbpos->ypos |= *cp++;
+       tbpos->xtilt = *cp++;
+       tbpos->ytilt = *cp++;
+       tbpos->scount++;
+}
+
+/*
+ * Decode old Hitachi 5 byte format (low res).
+ */
+static
+tbdecode(tc, cp, tbpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct tbpos *tbpos;
+{
+       register char byte;
+
+       byte = *cp++;
+       tbpos->status = (byte&0100) ? TBINPROX : 0;
+       byte &= ~0100;
+       if (byte > 036)
+               tbpos->status |= 1 << ((byte-040)/2);
+       tbpos->xpos = *cp++ << 7;
+       tbpos->xpos |= *cp++;
+       if (tbpos->xpos < 256)                  /* tablet wraps around at 256 */
+               tbpos->status &= ~TBINPROX;     /* make it out of proximity */
+       tbpos->ypos = *cp++ << 7;
+       tbpos->ypos |= *cp++;
+       tbpos->scount++;
+}
+
+/*
+ * Decode new Hitach 5-byte format (low res).
+ */
+static
+tblresdecode(tc, cp, tbpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct tbpos *tbpos;
+{
+
+       *cp &= ~0100;           /* mask sync bit */
+       tbpos->status = (*cp++ >> 2) | TBINPROX;
+       if (tc->tbc_flags&TBF_INPROX && tbpos->status&020)
+               tbpos->status &= ~(020|TBINPROX);
+       tbpos->xpos = *cp++;
+       tbpos->xpos |= *cp++ << 6;
+       tbpos->ypos = *cp++;
+       tbpos->ypos |= *cp++ << 6;
+       tbpos->scount++;
+}
+
+/*
+ * Decode new Hitach 6-byte format (high res).
+ */
+static
+tbhresdecode(tc, cp, tbpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct tbpos *tbpos;
+{
+       char byte;
+
+       byte = *cp++;
+       tbpos->xpos = (byte & 03) << 14;
+       tbpos->xpos |= *cp++ << 7;
+       tbpos->xpos |= *cp++;
+       tbpos->ypos = *cp++ << 14;
+       tbpos->ypos |= *cp++ << 7;
+       tbpos->ypos |= *cp++;
+       tbpos->status = (byte >> 2) | TBINPROX;
+       if (tc->tbc_flags&TBF_INPROX && tbpos->status&020)
+               tbpos->status &= ~(020|TBINPROX);
+       tbpos->scount++;
+}
+
+/*
+ * Polhemus decode.
+ */
+static
+poldecode(tc, cp, polpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct polpos *polpos;
+{
+
+       polpos->p_x = cp[4] | cp[3]<<7 | (cp[9] & 0x03) << 14;
+       polpos->p_y = cp[6] | cp[5]<<7 | (cp[9] & 0x0c) << 12;
+       polpos->p_z = cp[8] | cp[7]<<7 | (cp[9] & 0x30) << 10;
+       polpos->p_azi = cp[11] | cp[10]<<7 | (cp[16] & 0x03) << 14;
+       polpos->p_pit = cp[13] | cp[12]<<7 | (cp[16] & 0x0c) << 12;
+       polpos->p_rol = cp[15] | cp[14]<<7 | (cp[16] & 0x30) << 10;
+       polpos->p_stat = cp[1] | cp[0]<<7;
+       if (cp[2] != ' ')
+               polpos->p_key = cp[2];
+}
+
+/*ARGSUSED*/
+tbioctl(tp, cmd, data, flag)
+       struct tty *tp;
+       caddr_t data;
+{
+       register struct tb *tbp = (struct tb *)tp->T_LINEP;
+
+       switch (cmd) {
+
+       case BIOGMODE:
+               *(int *)data = tbp->tbflags & TBMODE;
+               break;
+
+       case BIOSTYPE:
+               if (tbconf[*(int *)data & TBTYPE].tbc_recsize == 0 ||
+                   tbconf[*(int *)data & TBTYPE].tbc_decode == 0)
+                       return (EINVAL);
+               tbp->tbflags &= ~TBTYPE;
+               tbp->tbflags |= *(int *)data & TBTYPE;
+               /* fall thru... to set mode bits */
+
+       case BIOSMODE: {
+               register struct tbconf *tc;
+
+               tbp->tbflags &= ~TBMODE;
+               tbp->tbflags |= *(int *)data & TBMODE;
+               tc = &tbconf[tbp->tbflags & TBTYPE];
+               if (tbp->tbflags&TBSTOP) {
+                       if (tc->tbc_stop)
+                               ttyout(tc->tbc_stop, tp);
+               } else if (tc->tbc_start)
+                       ttyout(tc->tbc_start, tp);
+               if (tbp->tbflags&TBPOINT) {
+                       if (tc->tbc_point)
+                               ttyout(tc->tbc_point, tp);
+               } else if (tc->tbc_run)
+                       ttyout(tc->tbc_run, tp);
+               ttstart(tp);
+               break;
+       }
+
+       case BIOGTYPE:
+               *(int *)data = tbp->tbflags & TBTYPE;
+               break;
+
+       case TIOCSETD:
+       case TIOCGETD:
+       case TIOCGETP:
+       case TIOCGETC:
+               return (-1);            /* pass thru... */
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+#endif
diff --git a/usr/src/sys.386bsd/kern/tty_tty.c b/usr/src/sys.386bsd/kern/tty_tty.c
new file mode 100644 (file)
index 0000000..4a0bed3
--- /dev/null
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tty_tty.c   7.15 (Berkeley) 5/28/91
+ */
+
+/*
+ * Indirect driver for controlling tty.
+ */
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "vnode.h"
+#include "file.h"
+
+#define cttyvp(p) ((p)->p_flag&SCTTY ? (p)->p_session->s_ttyvp : NULL)
+
+/*ARGSUSED*/
+cttyopen(dev, flag, mode, p)
+       dev_t dev;
+       int flag, mode;
+       struct proc *p;
+{
+       struct vnode *ttyvp = cttyvp(p);
+       int error;
+
+       if (ttyvp == NULL)
+               return (ENXIO);
+       VOP_LOCK(ttyvp);
+       error = VOP_ACCESS(ttyvp,
+         (flag&FREAD ? VREAD : 0) | (flag&FWRITE ? VWRITE : 0), p->p_ucred, p);
+       if (!error)
+               error = VOP_OPEN(ttyvp, flag, NOCRED, p);
+       VOP_UNLOCK(ttyvp);
+       return (error);
+}
+
+/*ARGSUSED*/
+cttyread(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct vnode *ttyvp = cttyvp(uio->uio_procp);
+       int error;
+
+       if (ttyvp == NULL)
+               return (EIO);
+       VOP_LOCK(ttyvp);
+       error = VOP_READ(ttyvp, uio, flag, NOCRED);
+       VOP_UNLOCK(ttyvp);
+       return (error);
+}
+
+/*ARGSUSED*/
+cttywrite(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct vnode *ttyvp = cttyvp(uio->uio_procp);
+       int error;
+
+       if (ttyvp == NULL)
+               return (EIO);
+       VOP_LOCK(ttyvp);
+       error = VOP_WRITE(ttyvp, uio, flag, NOCRED);
+       VOP_UNLOCK(ttyvp);
+       return (error);
+}
+
+/*ARGSUSED*/
+cttyioctl(dev, cmd, addr, flag, p)
+       dev_t dev;
+       int cmd;
+       caddr_t addr;
+       int flag;
+       struct proc *p;
+{
+       struct vnode *ttyvp = cttyvp(p);
+
+       if (ttyvp == NULL)
+               return (EIO);
+       if (cmd == TIOCNOTTY) {
+               if (!SESS_LEADER(p)) {
+                       p->p_flag &= ~SCTTY;
+                       return (0);
+               } else
+                       return (EINVAL);
+       }
+       return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, p));
+}
+
+/*ARGSUSED*/
+cttyselect(dev, flag, p)
+       dev_t dev;
+       int flag;
+       struct proc *p;
+{
+       struct vnode *ttyvp = cttyvp(p);
+
+       if (ttyvp == NULL)
+               return (1);     /* try operation to get EOF/failure */
+       return (VOP_SELECT(ttyvp, flag, FREAD|FWRITE, NOCRED, p));
+}
diff --git a/usr/src/sys.386bsd/kern/uipc_domain.c b/usr/src/sys.386bsd/kern/uipc_domain.c
new file mode 100644 (file)
index 0000000..f8ca170
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)uipc_domain.c       7.9 (Berkeley) 3/4/91
+ */
+
+#include <sys/cdefs.h>
+#include "param.h"
+#include "socket.h"
+#include "protosw.h"
+#include "domain.h"
+#include "mbuf.h"
+#include "time.h"
+#include "kernel.h"
+
+#define        ADDDOMAIN(x)    { \
+       extern struct domain __CONCAT(x,domain); \
+       __CONCAT(x,domain.dom_next) = domains; \
+       domains = &__CONCAT(x,domain); \
+}
+
+domaininit()
+{
+       register struct domain *dp;
+       register struct protosw *pr;
+
+#undef unix
+#ifndef lint
+       ADDDOMAIN(unix);
+       ADDDOMAIN(route);
+#ifdef INET
+       ADDDOMAIN(inet);
+#endif
+#ifdef NS
+       ADDDOMAIN(ns);
+#endif
+#ifdef ISO
+       ADDDOMAIN(iso);
+#endif
+#ifdef RMP
+       ADDDOMAIN(rmp);
+#endif
+#ifdef CCITT
+       ADDDOMAIN(ccitt);
+#endif
+#include "imp.h"
+#if NIMP > 0
+       ADDDOMAIN(imp);
+#endif
+#endif
+
+       for (dp = domains; dp; dp = dp->dom_next) {
+               if (dp->dom_init)
+                       (*dp->dom_init)();
+               for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
+                       if (pr->pr_init)
+                               (*pr->pr_init)();
+       }
+
+if (max_linkhdr < 16)          /* XXX */
+max_linkhdr = 16;
+       max_hdr = max_linkhdr + max_protohdr;
+       max_datalen = MHLEN - max_hdr;
+       pffasttimo();
+       pfslowtimo();
+}
+
+struct protosw *
+pffindtype(family, type)
+       int family, type;
+{
+       register struct domain *dp;
+       register struct protosw *pr;
+
+       for (dp = domains; dp; dp = dp->dom_next)
+               if (dp->dom_family == family)
+                       goto found;
+       return (0);
+found:
+       for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
+               if (pr->pr_type && pr->pr_type == type)
+                       return (pr);
+       return (0);
+}
+
+struct protosw *
+pffindproto(family, protocol, type)
+       int family, protocol, type;
+{
+       register struct domain *dp;
+       register struct protosw *pr;
+       struct protosw *maybe = 0;
+
+       if (family == 0)
+               return (0);
+       for (dp = domains; dp; dp = dp->dom_next)
+               if (dp->dom_family == family)
+                       goto found;
+       return (0);
+found:
+       for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
+               if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
+                       return (pr);
+
+               if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
+                   pr->pr_protocol == 0 && maybe == (struct protosw *)0)
+                       maybe = pr;
+       }
+       return (maybe);
+}
+
+pfctlinput(cmd, sa)
+       int cmd;
+       struct sockaddr *sa;
+{
+       register struct domain *dp;
+       register struct protosw *pr;
+
+       for (dp = domains; dp; dp = dp->dom_next)
+               for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
+                       if (pr->pr_ctlinput)
+                               (*pr->pr_ctlinput)(cmd, sa, (caddr_t) 0);
+}
+
+pfslowtimo()
+{
+       register struct domain *dp;
+       register struct protosw *pr;
+
+       for (dp = domains; dp; dp = dp->dom_next)
+               for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
+                       if (pr->pr_slowtimo)
+                               (*pr->pr_slowtimo)();
+       timeout(pfslowtimo, (caddr_t)0, hz/2);
+}
+
+pffasttimo()
+{
+       register struct domain *dp;
+       register struct protosw *pr;
+
+       for (dp = domains; dp; dp = dp->dom_next)
+               for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
+                       if (pr->pr_fasttimo)
+                               (*pr->pr_fasttimo)();
+       timeout(pffasttimo, (caddr_t)0, hz/5);
+}
diff --git a/usr/src/sys.386bsd/kern/uipc_proto.c b/usr/src/sys.386bsd/kern/uipc_proto.c
new file mode 100644 (file)
index 0000000..fd1dbae
--- /dev/null
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)uipc_proto.c        7.6 (Berkeley) 5/9/91
+ */
+
+#include "param.h"
+#include "socket.h"
+#include "protosw.h"
+#include "domain.h"
+#include "mbuf.h"
+
+/*
+ * Definitions of protocols supported in the UNIX domain.
+ */
+
+int    uipc_usrreq();
+int    raw_init(),raw_usrreq(),raw_input(),raw_ctlinput();
+extern struct domain unixdomain;               /* or at least forward */
+
+struct protosw unixsw[] = {
+{ SOCK_STREAM, &unixdomain,    0,      PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS,
+  0,           0,              0,              0,
+  uipc_usrreq,
+  0,           0,              0,              0,
+},
+{ SOCK_DGRAM,  &unixdomain,    0,              PR_ATOMIC|PR_ADDR|PR_RIGHTS,
+  0,           0,              0,              0,
+  uipc_usrreq,
+  0,           0,              0,              0,
+},
+{ 0,           0,              0,              0,
+  raw_input,   0,              raw_ctlinput,   0,
+  raw_usrreq,
+  raw_init,    0,              0,              0,
+}
+};
+
+int    unp_externalize(), unp_dispose();
+
+struct domain unixdomain =
+    { AF_UNIX, "unix", 0, unp_externalize, unp_dispose,
+      unixsw, &unixsw[sizeof(unixsw)/sizeof(unixsw[0])] };
diff --git a/usr/src/sys.386bsd/kern/uipc_socket.c b/usr/src/sys.386bsd/kern/uipc_socket.c
new file mode 100644 (file)
index 0000000..38a32b1
--- /dev/null
@@ -0,0 +1,991 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)uipc_socket.c       7.28 (Berkeley) 5/4/91
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "file.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "domain.h"
+#include "kernel.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "resourcevar.h"
+
+/*
+ * Socket operation routines.
+ * These routines are called by the routines in
+ * sys_socket.c or from a system process, and
+ * implement the semantics of socket operations by
+ * switching out to the protocol specific routines.
+ */
+/*ARGSUSED*/
+socreate(dom, aso, type, proto)
+       struct socket **aso;
+       register int type;
+       int proto;
+{
+       struct proc *p = curproc;               /* XXX */
+       register struct protosw *prp;
+       register struct socket *so;
+       register int error;
+
+       if (proto)
+               prp = pffindproto(dom, proto, type);
+       else
+               prp = pffindtype(dom, type);
+       if (prp == 0)
+               return (EPROTONOSUPPORT);
+       if (prp->pr_type != type)
+               return (EPROTOTYPE);
+       MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
+       bzero((caddr_t)so, sizeof(*so));
+       so->so_type = type;
+       if (p->p_ucred->cr_uid == 0)
+               so->so_state = SS_PRIV;
+       so->so_proto = prp;
+       error =
+           (*prp->pr_usrreq)(so, PRU_ATTACH,
+               (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
+       if (error) {
+               so->so_state |= SS_NOFDREF;
+               sofree(so);
+               return (error);
+       }
+       *aso = so;
+       return (0);
+}
+
+sobind(so, nam)
+       struct socket *so;
+       struct mbuf *nam;
+{
+       int s = splnet();
+       int error;
+
+       error =
+           (*so->so_proto->pr_usrreq)(so, PRU_BIND,
+               (struct mbuf *)0, nam, (struct mbuf *)0);
+       splx(s);
+       return (error);
+}
+
+solisten(so, backlog)
+       register struct socket *so;
+       int backlog;
+{
+       int s = splnet(), error;
+
+       error =
+           (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
+               (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
+       if (error) {
+               splx(s);
+               return (error);
+       }
+       if (so->so_q == 0)
+               so->so_options |= SO_ACCEPTCONN;
+       if (backlog < 0)
+               backlog = 0;
+       so->so_qlimit = min(backlog, SOMAXCONN);
+       splx(s);
+       return (0);
+}
+
+sofree(so)
+       register struct socket *so;
+{
+
+       if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
+               return;
+       if (so->so_head) {
+               if (!soqremque(so, 0) && !soqremque(so, 1))
+                       panic("sofree dq");
+               so->so_head = 0;
+       }
+       sbrelease(&so->so_snd);
+       sorflush(so);
+       FREE(so, M_SOCKET);
+}
+
+/*
+ * Close a socket on last file table reference removal.
+ * Initiate disconnect if connected.
+ * Free socket when disconnect complete.
+ */
+soclose(so)
+       register struct socket *so;
+{
+       int s = splnet();               /* conservative */
+       int error = 0;
+
+       if (so->so_options & SO_ACCEPTCONN) {
+               while (so->so_q0)
+                       (void) soabort(so->so_q0);
+               while (so->so_q)
+                       (void) soabort(so->so_q);
+       }
+       if (so->so_pcb == 0)
+               goto discard;
+       if (so->so_state & SS_ISCONNECTED) {
+               if ((so->so_state & SS_ISDISCONNECTING) == 0) {
+                       error = sodisconnect(so);
+                       if (error)
+                               goto drop;
+               }
+               if (so->so_options & SO_LINGER) {
+                       if ((so->so_state & SS_ISDISCONNECTING) &&
+                           (so->so_state & SS_NBIO))
+                               goto drop;
+                       while (so->so_state & SS_ISCONNECTED)
+                               if (error = tsleep((caddr_t)&so->so_timeo,
+                                   PSOCK | PCATCH, netcls, so->so_linger))
+                                       break;
+               }
+       }
+drop:
+       if (so->so_pcb) {
+               int error2 =
+                   (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
+                       (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
+               if (error == 0)
+                       error = error2;
+       }
+discard:
+       if (so->so_state & SS_NOFDREF)
+               panic("soclose: NOFDREF");
+       so->so_state |= SS_NOFDREF;
+       sofree(so);
+       splx(s);
+       return (error);
+}
+
+/*
+ * Must be called at splnet...
+ */
+soabort(so)
+       struct socket *so;
+{
+
+       return (
+           (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
+               (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
+}
+
+soaccept(so, nam)
+       register struct socket *so;
+       struct mbuf *nam;
+{
+       int s = splnet();
+       int error;
+
+       if ((so->so_state & SS_NOFDREF) == 0)
+               panic("soaccept: !NOFDREF");
+       so->so_state &= ~SS_NOFDREF;
+       error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
+           (struct mbuf *)0, nam, (struct mbuf *)0);
+       splx(s);
+       return (error);
+}
+
+soconnect(so, nam)
+       register struct socket *so;
+       struct mbuf *nam;
+{
+       int s;
+       int error;
+
+       if (so->so_options & SO_ACCEPTCONN)
+               return (EOPNOTSUPP);
+       s = splnet();
+       /*
+        * If protocol is connection-based, can only connect once.
+        * Otherwise, if connected, try to disconnect first.
+        * This allows user to disconnect by connecting to, e.g.,
+        * a null address.
+        */
+       if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
+           ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
+           (error = sodisconnect(so))))
+               error = EISCONN;
+       else
+               error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
+                   (struct mbuf *)0, nam, (struct mbuf *)0);
+       splx(s);
+       return (error);
+}
+
+soconnect2(so1, so2)
+       register struct socket *so1;
+       struct socket *so2;
+{
+       int s = splnet();
+       int error;
+
+       error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
+           (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
+       splx(s);
+       return (error);
+}
+
+sodisconnect(so)
+       register struct socket *so;
+{
+       int s = splnet();
+       int error;
+
+       if ((so->so_state & SS_ISCONNECTED) == 0) {
+               error = ENOTCONN;
+               goto bad;
+       }
+       if (so->so_state & SS_ISDISCONNECTING) {
+               error = EALREADY;
+               goto bad;
+       }
+       error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
+           (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
+bad:
+       splx(s);
+       return (error);
+}
+
+/*
+ * Send on a socket.
+ * If send must go all at once and message is larger than
+ * send buffering, then hard error.
+ * Lock against other senders.
+ * If must go all at once and not enough room now, then
+ * inform user that this would block and do nothing.
+ * Otherwise, if nonblocking, send as much as possible.
+ * The data to be sent is described by "uio" if nonzero,
+ * otherwise by the mbuf chain "top" (which must be null
+ * if uio is not).  Data provided in mbuf chain must be small
+ * enough to send all at once.
+ *
+ * Returns nonzero on error, timeout or signal; callers
+ * must check for short counts if EINTR/ERESTART are returned.
+ * Data and control buffers are freed on return.
+ */
+sosend(so, addr, uio, top, control, flags)
+       register struct socket *so;
+       struct mbuf *addr;
+       struct uio *uio;
+       struct mbuf *top;
+       struct mbuf *control;
+       int flags;
+{
+       struct proc *p = curproc;               /* XXX */
+       struct mbuf **mp;
+       register struct mbuf *m;
+       register long space, len, resid;
+       int clen = 0, error, s, dontroute, mlen;
+       int atomic = sosendallatonce(so) || top;
+
+       if (uio)
+               resid = uio->uio_resid;
+       else
+               resid = top->m_pkthdr.len;
+       dontroute =
+           (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
+           (so->so_proto->pr_flags & PR_ATOMIC);
+       p->p_stats->p_ru.ru_msgsnd++;
+       if (control)
+               clen = control->m_len;
+#define        snderr(errno)   { error = errno; splx(s); goto release; }
+
+restart:
+       if (error = sblock(&so->so_snd))
+               goto out;
+       do {
+               s = splnet();
+               if (so->so_state & SS_CANTSENDMORE)
+                       snderr(EPIPE);
+               if (so->so_error)
+                       snderr(so->so_error);
+               if ((so->so_state & SS_ISCONNECTED) == 0) {
+                       if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+                               if ((so->so_state & SS_ISCONFIRMING) == 0 &&
+                                   !(resid == 0 && clen != 0))
+                                       snderr(ENOTCONN);
+                       } else if (addr == 0)
+                               snderr(EDESTADDRREQ);
+               }
+               space = sbspace(&so->so_snd);
+               if (flags & MSG_OOB)
+                       space += 1024;
+               if (space < resid + clen &&
+                   (atomic || space < so->so_snd.sb_lowat || space < clen)) {
+                       if (atomic && resid > so->so_snd.sb_hiwat ||
+                           clen > so->so_snd.sb_hiwat)
+                               snderr(EMSGSIZE);
+                       if (so->so_state & SS_NBIO)
+                               snderr(EWOULDBLOCK);
+                       sbunlock(&so->so_snd);
+                       error = sbwait(&so->so_snd);
+                       splx(s);
+                       if (error)
+                               goto out;
+                       goto restart;
+               }
+               splx(s);
+               mp = &top;
+               space -= clen;
+               do {
+                   if (uio == NULL) {
+                       /*
+                        * Data is prepackaged in "top".
+                        */
+                       resid = 0;
+                       if (flags & MSG_EOR)
+                               top->m_flags |= M_EOR;
+                   } else do {
+                       if (top == 0) {
+                               MGETHDR(m, M_WAIT, MT_DATA);
+                               mlen = MHLEN;
+                               m->m_pkthdr.len = 0;
+                               m->m_pkthdr.rcvif = (struct ifnet *)0;
+                       } else {
+                               MGET(m, M_WAIT, MT_DATA);
+                               mlen = MLEN;
+                       }
+                       if (resid >= MINCLSIZE && space >= MCLBYTES) {
+                               MCLGET(m, M_WAIT);
+                               if ((m->m_flags & M_EXT) == 0)
+                                       goto nopages;
+                               mlen = MCLBYTES;
+#ifdef MAPPED_MBUFS
+                               len = min(MCLBYTES, resid);
+#else
+                               if (top == 0) {
+                                       len = min(MCLBYTES - max_hdr, resid);
+                                       m->m_data += max_hdr;
+                               } else
+                                       len = min(MCLBYTES, resid);
+#endif
+                               space -= MCLBYTES;
+                       } else {
+nopages:
+                               len = min(min(mlen, resid), space);
+                               space -= len;
+                               /*
+                                * For datagram protocols, leave room
+                                * for protocol headers in first mbuf.
+                                */
+                               if (atomic && top == 0 && len < mlen)
+                                       MH_ALIGN(m, len);
+                       }
+                       error = uiomove(mtod(m, caddr_t), (int)len, uio);
+                       resid = uio->uio_resid;
+                       m->m_len = len;
+                       *mp = m;
+                       top->m_pkthdr.len += len;
+                       if (error)
+                               goto release;
+                       mp = &m->m_next;
+                       if (resid <= 0) {
+                               if (flags & MSG_EOR)
+                                       top->m_flags |= M_EOR;
+                               break;
+                       }
+                   } while (space > 0 && atomic);
+                   if (dontroute)
+                           so->so_options |= SO_DONTROUTE;
+                   s = splnet();                               /* XXX */
+                   error = (*so->so_proto->pr_usrreq)(so,
+                       (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
+                       top, addr, control);
+                   splx(s);
+                   if (dontroute)
+                           so->so_options &= ~SO_DONTROUTE;
+                   clen = 0;
+                   control = 0;
+                   top = 0;
+                   mp = &top;
+                   if (error)
+                       goto release;
+               } while (resid && space > 0);
+       } while (resid);
+
+release:
+       sbunlock(&so->so_snd);
+out:
+       if (top)
+               m_freem(top);
+       if (control)
+               m_freem(control);
+       return (error);
+}
+
+/*
+ * Implement receive operations on a socket.
+ * We depend on the way that records are added to the sockbuf
+ * by sbappend*.  In particular, each record (mbufs linked through m_next)
+ * must begin with an address if the protocol so specifies,
+ * followed by an optional mbuf or mbufs containing ancillary data,
+ * and then zero or more mbufs of data.
+ * In order to avoid blocking network interrupts for the entire time here,
+ * we splx() while doing the actual copy to user space.
+ * Although the sockbuf is locked, new data may still be appended,
+ * and thus we must maintain consistency of the sockbuf during that time.
+ *
+ * The caller may receive the data as a single mbuf chain by supplying
+ * an mbuf **mp0 for use in returning the chain.  The uio is then used
+ * only for the count in uio_resid.
+ */
+soreceive(so, paddr, uio, mp0, controlp, flagsp)
+       register struct socket *so;
+       struct mbuf **paddr;
+       struct uio *uio;
+       struct mbuf **mp0;
+       struct mbuf **controlp;
+       int *flagsp;
+{
+       struct proc *p = curproc;               /* XXX */
+       register struct mbuf *m, **mp;
+       register int flags, len, error, s, offset;
+       struct protosw *pr = so->so_proto;
+       struct mbuf *nextrecord;
+       int moff, type;
+
+       mp = mp0;
+       if (paddr)
+               *paddr = 0;
+       if (controlp)
+               *controlp = 0;
+       if (flagsp)
+               flags = *flagsp &~ MSG_EOR;
+       else
+               flags = 0;
+       if (flags & MSG_OOB) {
+               m = m_get(M_WAIT, MT_DATA);
+               error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
+                   m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
+               if (error)
+                       goto bad;
+               do {
+                       error = uiomove(mtod(m, caddr_t),
+                           (int) min(uio->uio_resid, m->m_len), uio);
+                       m = m_free(m);
+               } while (uio->uio_resid && error == 0 && m);
+bad:
+               if (m)
+                       m_freem(m);
+               return (error);
+       }
+       if (mp)
+               *mp = (struct mbuf *)0;
+       if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
+               (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
+                   (struct mbuf *)0, (struct mbuf *)0);
+
+restart:
+       if (error = sblock(&so->so_rcv))
+               return (error);
+       s = splnet();
+
+       m = so->so_rcv.sb_mb;
+       /*
+        * If we have less data than requested, block awaiting more
+        * (subject to any timeout) if:
+        *   1. the current count is less than the low water mark, or
+        *   2. MSG_WAITALL is set, and it is possible to do the entire
+        *      receive operation at once if we block (resid <= hiwat).
+        * If MSG_WAITALL is set but resid is larger than the receive buffer,
+        * we have to do the receive in sections, and thus risk returning
+        * a short count if a timeout or signal occurs after we start.
+        */
+       while (m == 0 || so->so_rcv.sb_cc < uio->uio_resid &&
+           (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
+           ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
+           m->m_nextpkt == 0) {
+#ifdef DIAGNOSTIC
+               if (m == 0 && so->so_rcv.sb_cc)
+                       panic("receive 1");
+#endif
+               if (so->so_error) {
+                       if (m)
+                               break;
+                       error = so->so_error;
+                       if ((flags & MSG_PEEK) == 0)
+                               so->so_error = 0;
+                       goto release;
+               }
+               if (so->so_state & SS_CANTRCVMORE) {
+                       if (m)
+                               break;
+                       else
+                               goto release;
+               }
+               for (; m; m = m->m_next)
+                       if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
+                               m = so->so_rcv.sb_mb;
+                               goto dontblock;
+                       }
+               if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
+                   (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
+                       error = ENOTCONN;
+                       goto release;
+               }
+               if (uio->uio_resid == 0)
+                       goto release;
+               if (so->so_state & SS_NBIO) {
+                       error = EWOULDBLOCK;
+                       goto release;
+               }
+               sbunlock(&so->so_rcv);
+               error = sbwait(&so->so_rcv);
+               splx(s);
+               if (error)
+                       return (error);
+               goto restart;
+       }
+dontblock:
+       p->p_stats->p_ru.ru_msgrcv++;
+       nextrecord = m->m_nextpkt;
+       if (pr->pr_flags & PR_ADDR) {
+#ifdef DIAGNOSTIC
+               if (m->m_type != MT_SONAME)
+                       panic("receive 1a");
+#endif
+               if (flags & MSG_PEEK) {
+                       if (paddr)
+                               *paddr = m_copy(m, 0, m->m_len);
+                       m = m->m_next;
+               } else {
+                       sbfree(&so->so_rcv, m);
+                       if (paddr) {
+                               *paddr = m;
+                               so->so_rcv.sb_mb = m->m_next;
+                               m->m_next = 0;
+                               m = so->so_rcv.sb_mb;
+                       } else {
+                               MFREE(m, so->so_rcv.sb_mb);
+                               m = so->so_rcv.sb_mb;
+                       }
+               }
+       }
+       while (m && m->m_type == MT_CONTROL && error == 0) {
+               if (flags & MSG_PEEK) {
+                       if (controlp)
+                               *controlp = m_copy(m, 0, m->m_len);
+                       m = m->m_next;
+               } else {
+                       sbfree(&so->so_rcv, m);
+                       if (controlp) {
+                               if (pr->pr_domain->dom_externalize &&
+                                   mtod(m, struct cmsghdr *)->cmsg_type ==
+                                   SCM_RIGHTS)
+                                  error = (*pr->pr_domain->dom_externalize)(m);
+                               *controlp = m;
+                               so->so_rcv.sb_mb = m->m_next;
+                               m->m_next = 0;
+                               m = so->so_rcv.sb_mb;
+                       } else {
+                               MFREE(m, so->so_rcv.sb_mb);
+                               m = so->so_rcv.sb_mb;
+                       }
+               }
+               if (controlp)
+                       controlp = &(*controlp)->m_next;
+       }
+       if (m) {
+               if ((flags & MSG_PEEK) == 0)
+                       m->m_nextpkt = nextrecord;
+               type = m->m_type;
+               if (type == MT_OOBDATA)
+                       flags |= MSG_OOB;
+       }
+       moff = 0;
+       offset = 0;
+       while (m && uio->uio_resid > 0 && error == 0) {
+               if (m->m_type == MT_OOBDATA) {
+                       if (type != MT_OOBDATA)
+                               break;
+               } else if (type == MT_OOBDATA)
+                       break;
+#ifdef DIAGNOSTIC
+               else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
+                       panic("receive 3");
+#endif
+               so->so_state &= ~SS_RCVATMARK;
+               len = uio->uio_resid;
+               if (so->so_oobmark && len > so->so_oobmark - offset)
+                       len = so->so_oobmark - offset;
+               if (len > m->m_len - moff)
+                       len = m->m_len - moff;
+               /*
+                * If mp is set, just pass back the mbufs.
+                * Otherwise copy them out via the uio, then free.
+                * Sockbuf must be consistent here (points to current mbuf,
+                * it points to next record) when we drop priority;
+                * we must note any additions to the sockbuf when we
+                * block interrupts again.
+                */
+               if (mp == 0) {
+                       splx(s);
+                       error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
+                       s = splnet();
+               } else
+                       uio->uio_resid -= len;
+               if (len == m->m_len - moff) {
+                       if (m->m_flags & M_EOR)
+                               flags |= MSG_EOR;
+                       if (flags & MSG_PEEK) {
+                               m = m->m_next;
+                               moff = 0;
+                       } else {
+                               nextrecord = m->m_nextpkt;
+                               sbfree(&so->so_rcv, m);
+                               if (mp) {
+                                       *mp = m;
+                                       mp = &m->m_next;
+                                       so->so_rcv.sb_mb = m = m->m_next;
+                                       *mp = (struct mbuf *)0;
+                               } else {
+                                       MFREE(m, so->so_rcv.sb_mb);
+                                       m = so->so_rcv.sb_mb;
+                               }
+                               if (m)
+                                       m->m_nextpkt = nextrecord;
+                       }
+               } else {
+                       if (flags & MSG_PEEK)
+                               moff += len;
+                       else {
+                               if (mp)
+                                       *mp = m_copym(m, 0, len, M_WAIT);
+                               m->m_data += len;
+                               m->m_len -= len;
+                               so->so_rcv.sb_cc -= len;
+                       }
+               }
+               if (so->so_oobmark) {
+                       if ((flags & MSG_PEEK) == 0) {
+                               so->so_oobmark -= len;
+                               if (so->so_oobmark == 0) {
+                                       so->so_state |= SS_RCVATMARK;
+                                       break;
+                               }
+                       } else
+                               offset += len;
+               }
+               if (flags & MSG_EOR)
+                       break;
+               /*
+                * If the MSG_WAITALL flag is set (for non-atomic socket),
+                * we must not quit until "uio->uio_resid == 0" or an error
+                * termination.  If a signal/timeout occurs, return
+                * with a short count but without error.
+                * Keep sockbuf locked against other readers.
+                */
+               while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
+                   !sosendallatonce(so)) {
+                       if (so->so_error || so->so_state & SS_CANTRCVMORE)
+                               break;
+                       error = sbwait(&so->so_rcv);
+                       if (error) {
+                               sbunlock(&so->so_rcv);
+                               splx(s);
+                               return (0);
+                       }
+                       if (m = so->so_rcv.sb_mb)
+                               nextrecord = m->m_nextpkt;
+               }
+       }
+       if ((flags & MSG_PEEK) == 0) {
+               if (m == 0)
+                       so->so_rcv.sb_mb = nextrecord;
+               else if (pr->pr_flags & PR_ATOMIC) {
+                       flags |= MSG_TRUNC;
+                       (void) sbdroprecord(&so->so_rcv);
+               }
+               if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
+                       (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
+                           (struct mbuf *)flags, (struct mbuf *)0,
+                           (struct mbuf *)0);
+       }
+       if (flagsp)
+               *flagsp |= flags;
+release:
+       sbunlock(&so->so_rcv);
+       splx(s);
+       return (error);
+}
+
+soshutdown(so, how)
+       register struct socket *so;
+       register int how;
+{
+       register struct protosw *pr = so->so_proto;
+
+       how++;
+       if (how & FREAD)
+               sorflush(so);
+       if (how & FWRITE)
+               return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
+                   (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
+       return (0);
+}
+
+sorflush(so)
+       register struct socket *so;
+{
+       register struct sockbuf *sb = &so->so_rcv;
+       register struct protosw *pr = so->so_proto;
+       register int s;
+       struct sockbuf asb;
+
+       sb->sb_flags |= SB_NOINTR;
+       (void) sblock(sb);
+       s = splimp();
+       socantrcvmore(so);
+       sbunlock(sb);
+       asb = *sb;
+       bzero((caddr_t)sb, sizeof (*sb));
+       splx(s);
+       if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
+               (*pr->pr_domain->dom_dispose)(asb.sb_mb);
+       sbrelease(&asb);
+}
+
+sosetopt(so, level, optname, m0)
+       register struct socket *so;
+       int level, optname;
+       struct mbuf *m0;
+{
+       int error = 0;
+       register struct mbuf *m = m0;
+
+       if (level != SOL_SOCKET) {
+               if (so->so_proto && so->so_proto->pr_ctloutput)
+                       return ((*so->so_proto->pr_ctloutput)
+                                 (PRCO_SETOPT, so, level, optname, &m0));
+               error = ENOPROTOOPT;
+       } else {
+               switch (optname) {
+
+               case SO_LINGER:
+                       if (m == NULL || m->m_len != sizeof (struct linger)) {
+                               error = EINVAL;
+                               goto bad;
+                       }
+                       so->so_linger = mtod(m, struct linger *)->l_linger;
+                       /* fall thru... */
+
+               case SO_DEBUG:
+               case SO_KEEPALIVE:
+               case SO_DONTROUTE:
+               case SO_USELOOPBACK:
+               case SO_BROADCAST:
+               case SO_REUSEADDR:
+               case SO_OOBINLINE:
+                       if (m == NULL || m->m_len < sizeof (int)) {
+                               error = EINVAL;
+                               goto bad;
+                       }
+                       if (*mtod(m, int *))
+                               so->so_options |= optname;
+                       else
+                               so->so_options &= ~optname;
+                       break;
+
+               case SO_SNDBUF:
+               case SO_RCVBUF:
+               case SO_SNDLOWAT:
+               case SO_RCVLOWAT:
+                       if (m == NULL || m->m_len < sizeof (int)) {
+                               error = EINVAL;
+                               goto bad;
+                       }
+                       switch (optname) {
+
+                       case SO_SNDBUF:
+                       case SO_RCVBUF:
+                               if (sbreserve(optname == SO_SNDBUF ?
+                                   &so->so_snd : &so->so_rcv,
+                                   (u_long) *mtod(m, int *)) == 0) {
+                                       error = ENOBUFS;
+                                       goto bad;
+                               }
+                               break;
+
+                       case SO_SNDLOWAT:
+                               so->so_snd.sb_lowat = *mtod(m, int *);
+                               break;
+                       case SO_RCVLOWAT:
+                               so->so_rcv.sb_lowat = *mtod(m, int *);
+                               break;
+                       }
+                       break;
+
+               case SO_SNDTIMEO:
+               case SO_RCVTIMEO:
+                   {
+                       struct timeval *tv;
+                       short val;
+
+                       if (m == NULL || m->m_len < sizeof (*tv)) {
+                               error = EINVAL;
+                               goto bad;
+                       }
+                       tv = mtod(m, struct timeval *);
+                       if (tv->tv_sec > SHRT_MAX / hz - hz) {
+                               error = EDOM;
+                               goto bad;
+                       }
+                       val = tv->tv_sec * hz + tv->tv_usec / tick;
+
+                       switch (optname) {
+
+                       case SO_SNDTIMEO:
+                               so->so_snd.sb_timeo = val;
+                               break;
+                       case SO_RCVTIMEO:
+                               so->so_rcv.sb_timeo = val;
+                               break;
+                       }
+                       break;
+                   }
+
+               default:
+                       error = ENOPROTOOPT;
+                       break;
+               }
+       }
+bad:
+       if (m)
+               (void) m_free(m);
+       return (error);
+}
+
+sogetopt(so, level, optname, mp)
+       register struct socket *so;
+       int level, optname;
+       struct mbuf **mp;
+{
+       register struct mbuf *m;
+
+       if (level != SOL_SOCKET) {
+               if (so->so_proto && so->so_proto->pr_ctloutput) {
+                       return ((*so->so_proto->pr_ctloutput)
+                                 (PRCO_GETOPT, so, level, optname, mp));
+               } else
+                       return (ENOPROTOOPT);
+       } else {
+               m = m_get(M_WAIT, MT_SOOPTS);
+               m->m_len = sizeof (int);
+
+               switch (optname) {
+
+               case SO_LINGER:
+                       m->m_len = sizeof (struct linger);
+                       mtod(m, struct linger *)->l_onoff =
+                               so->so_options & SO_LINGER;
+                       mtod(m, struct linger *)->l_linger = so->so_linger;
+                       break;
+
+               case SO_USELOOPBACK:
+               case SO_DONTROUTE:
+               case SO_DEBUG:
+               case SO_KEEPALIVE:
+               case SO_REUSEADDR:
+               case SO_BROADCAST:
+               case SO_OOBINLINE:
+                       *mtod(m, int *) = so->so_options & optname;
+                       break;
+
+               case SO_TYPE:
+                       *mtod(m, int *) = so->so_type;
+                       break;
+
+               case SO_ERROR:
+                       *mtod(m, int *) = so->so_error;
+                       so->so_error = 0;
+                       break;
+
+               case SO_SNDBUF:
+                       *mtod(m, int *) = so->so_snd.sb_hiwat;
+                       break;
+
+               case SO_RCVBUF:
+                       *mtod(m, int *) = so->so_rcv.sb_hiwat;
+                       break;
+
+               case SO_SNDLOWAT:
+                       *mtod(m, int *) = so->so_snd.sb_lowat;
+                       break;
+
+               case SO_RCVLOWAT:
+                       *mtod(m, int *) = so->so_rcv.sb_lowat;
+                       break;
+
+               case SO_SNDTIMEO:
+               case SO_RCVTIMEO:
+                   {
+                       int val = (optname == SO_SNDTIMEO ?
+                            so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
+
+                       m->m_len = sizeof(struct timeval);
+                       mtod(m, struct timeval *)->tv_sec = val / hz;
+                       mtod(m, struct timeval *)->tv_usec =
+                           (val % hz) / tick;
+                       break;
+                   }
+
+               default:
+                       (void)m_free(m);
+                       return (ENOPROTOOPT);
+               }
+               *mp = m;
+               return (0);
+       }
+}
+
+sohasoutofband(so)
+       register struct socket *so;
+{
+       struct proc *p;
+
+       if (so->so_pgid < 0)
+               gsignal(-so->so_pgid, SIGURG);
+       else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
+               psignal(p, SIGURG);
+       if (so->so_rcv.sb_sel) {
+               selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
+               so->so_rcv.sb_sel = 0;
+               so->so_rcv.sb_flags &= ~SB_COLL;
+       }
+}
diff --git a/usr/src/sys.386bsd/kern/uipc_socket2.c b/usr/src/sys.386bsd/kern/uipc_socket2.c
new file mode 100644 (file)
index 0000000..9c4481d
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)uipc_socket2.c      7.17 (Berkeley) 5/4/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "file.h"
+#include "buf.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+
+/*
+ * Primitive routines for operating on sockets and socket buffers
+ */
+
+/* strings for sleep message: */
+char   netio[] = "netio";
+char   netcon[] = "netcon";
+char   netcls[] = "netcls";
+
+u_long sb_max = SB_MAX;                /* patchable */
+
+/*
+ * Procedures to manipulate state flags of socket
+ * and do appropriate wakeups.  Normal sequence from the
+ * active (originating) side is that soisconnecting() is
+ * called during processing of connect() call,
+ * resulting in an eventual call to soisconnected() if/when the
+ * connection is established.  When the connection is torn down
+ * soisdisconnecting() is called during processing of disconnect() call,
+ * and soisdisconnected() is called when the connection to the peer
+ * is totally severed.  The semantics of these routines are such that
+ * connectionless protocols can call soisconnected() and soisdisconnected()
+ * only, bypassing the in-progress calls when setting up a ``connection''
+ * takes no time.
+ *
+ * From the passive side, a socket is created with
+ * two queues of sockets: so_q0 for connections in progress
+ * and so_q for connections already made and awaiting user acceptance.
+ * As a protocol is preparing incoming connections, it creates a socket
+ * structure queued on so_q0 by calling sonewconn().  When the connection
+ * is established, soisconnected() is called, and transfers the
+ * socket structure to so_q, making it available to accept().
+ * 
+ * If a socket is closed with sockets on either
+ * so_q0 or so_q, these sockets are dropped.
+ *
+ * If higher level protocols are implemented in
+ * the kernel, the wakeups done here will sometimes
+ * cause software-interrupt process scheduling.
+ */
+
+soisconnecting(so)
+       register struct socket *so;
+{
+
+       so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
+       so->so_state |= SS_ISCONNECTING;
+}
+
+soisconnected(so)
+       register struct socket *so;
+{
+       register struct socket *head = so->so_head;
+
+       so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
+       so->so_state |= SS_ISCONNECTED;
+       if (head && soqremque(so, 0)) {
+               soqinsque(head, so, 1);
+               sorwakeup(head);
+               wakeup((caddr_t)&head->so_timeo);
+       } else {
+               wakeup((caddr_t)&so->so_timeo);
+               sorwakeup(so);
+               sowwakeup(so);
+       }
+}
+
+soisdisconnecting(so)
+       register struct socket *so;
+{
+
+       so->so_state &= ~SS_ISCONNECTING;
+       so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
+       wakeup((caddr_t)&so->so_timeo);
+       sowwakeup(so);
+       sorwakeup(so);
+}
+
+soisdisconnected(so)
+       register struct socket *so;
+{
+
+       so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
+       so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
+       wakeup((caddr_t)&so->so_timeo);
+       sowwakeup(so);
+       sorwakeup(so);
+}
+
+/*
+ * When an attempt at a new connection is noted on a socket
+ * which accepts connections, sonewconn is called.  If the
+ * connection is possible (subject to space constraints, etc.)
+ * then we allocate a new structure, propoerly linked into the
+ * data structure of the original socket, and return this.
+ * Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED.
+ *
+ * Currently, sonewconn() is defined as sonewconn1() in socketvar.h
+ * to catch calls that are missing the (new) second parameter.
+ */
+struct socket *
+sonewconn1(head, connstatus)
+       register struct socket *head;
+       int connstatus;
+{
+       register struct socket *so;
+       int soqueue = connstatus ? 1 : 0;
+
+       if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2)
+               return ((struct socket *)0);
+       MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT);
+       if (so == NULL) 
+               return ((struct socket *)0);
+       bzero((caddr_t)so, sizeof(*so));
+       so->so_type = head->so_type;
+       so->so_options = head->so_options &~ SO_ACCEPTCONN;
+       so->so_linger = head->so_linger;
+       so->so_state = head->so_state | SS_NOFDREF;
+       so->so_proto = head->so_proto;
+       so->so_timeo = head->so_timeo;
+       so->so_pgid = head->so_pgid;
+       (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat);
+       soqinsque(head, so, soqueue);
+       if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH,
+           (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) {
+               (void) soqremque(so, soqueue);
+               (void) free((caddr_t)so, M_SOCKET);
+               return ((struct socket *)0);
+       }
+       if (connstatus) {
+               sorwakeup(head);
+               wakeup((caddr_t)&head->so_timeo);
+               so->so_state |= connstatus;
+       }
+       return (so);
+}
+
+soqinsque(head, so, q)
+       register struct socket *head, *so;
+       int q;
+{
+
+       register struct socket **prev;
+       so->so_head = head;
+       if (q == 0) {
+               head->so_q0len++;
+               so->so_q0 = 0;
+               for (prev = &(head->so_q0); *prev; )
+                       prev = &((*prev)->so_q0);
+       } else {
+               head->so_qlen++;
+               so->so_q = 0;
+               for (prev = &(head->so_q); *prev; )
+                       prev = &((*prev)->so_q);
+       }
+       *prev = so;
+}
+
+soqremque(so, q)
+       register struct socket *so;
+       int q;
+{
+       register struct socket *head, *prev, *next;
+
+       head = so->so_head;
+       prev = head;
+       for (;;) {
+               next = q ? prev->so_q : prev->so_q0;
+               if (next == so)
+                       break;
+               if (next == 0)
+                       return (0);
+               prev = next;
+       }
+       if (q == 0) {
+               prev->so_q0 = next->so_q0;
+               head->so_q0len--;
+       } else {
+               prev->so_q = next->so_q;
+               head->so_qlen--;
+       }
+       next->so_q0 = next->so_q = 0;
+       next->so_head = 0;
+       return (1);
+}
+
+/*
+ * Socantsendmore indicates that no more data will be sent on the
+ * socket; it would normally be applied to a socket when the user
+ * informs the system that no more data is to be sent, by the protocol
+ * code (in case PRU_SHUTDOWN).  Socantrcvmore indicates that no more data
+ * will be received, and will normally be applied to the socket by a
+ * protocol when it detects that the peer will send no more data.
+ * Data queued for reading in the socket may yet be read.
+ */
+
+socantsendmore(so)
+       struct socket *so;
+{
+
+       so->so_state |= SS_CANTSENDMORE;
+       sowwakeup(so);
+}
+
+socantrcvmore(so)
+       struct socket *so;
+{
+
+       so->so_state |= SS_CANTRCVMORE;
+       sorwakeup(so);
+}
+
+/*
+ * Socket select/wakeup routines.
+ */
+
+/*
+ * Queue a process for a select on a socket buffer.
+ */
+sbselqueue(sb, cp)
+       struct sockbuf *sb;
+       struct proc *cp;
+{
+       struct proc *p;
+
+       if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)&selwait)
+               sb->sb_flags |= SB_COLL;
+       else {
+               sb->sb_sel = cp;
+               sb->sb_flags |= SB_SEL;
+       }
+}
+
+/*
+ * Wait for data to arrive at/drain from a socket buffer.
+ */
+sbwait(sb)
+       struct sockbuf *sb;
+{
+
+       sb->sb_flags |= SB_WAIT;
+       return (tsleep((caddr_t)&sb->sb_cc,
+           (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, netio,
+           sb->sb_timeo));
+}
+
+/* 
+ * Lock a sockbuf already known to be locked;
+ * return any error returned from sleep (EINTR).
+ */
+sb_lock(sb)
+       register struct sockbuf *sb;
+{
+       int error;
+
+       while (sb->sb_flags & SB_LOCK) {
+               sb->sb_flags |= SB_WANT;
+               if (error = tsleep((caddr_t)&sb->sb_flags, 
+                   (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH,
+                   netio, 0))
+                       return (error);
+       }
+       sb->sb_flags |= SB_LOCK;
+       return (0);
+}
+
+/*
+ * Wakeup processes waiting on a socket buffer.
+ * Do asynchronous notification via SIGIO
+ * if the socket has the SS_ASYNC flag set.
+ */
+sowakeup(so, sb)
+       register struct socket *so;
+       register struct sockbuf *sb;
+{
+       struct proc *p;
+
+       if (sb->sb_sel) {
+               selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
+               sb->sb_sel = 0;
+               sb->sb_flags &= ~(SB_SEL|SB_COLL);
+       }
+       if (sb->sb_flags & SB_WAIT) {
+               sb->sb_flags &= ~SB_WAIT;
+               wakeup((caddr_t)&sb->sb_cc);
+       }
+       if (so->so_state & SS_ASYNC) {
+               if (so->so_pgid < 0)
+                       gsignal(-so->so_pgid, SIGIO);
+               else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
+                       psignal(p, SIGIO);
+       }
+}
+
+/*
+ * Socket buffer (struct sockbuf) utility routines.
+ *
+ * Each socket contains two socket buffers: one for sending data and
+ * one for receiving data.  Each buffer contains a queue of mbufs,
+ * information about the number of mbufs and amount of data in the
+ * queue, and other fields allowing select() statements and notification
+ * on data availability to be implemented.
+ *
+ * Data stored in a socket buffer is maintained as a list of records.
+ * Each record is a list of mbufs chained together with the m_next
+ * field.  Records are chained together with the m_nextpkt field. The upper
+ * level routine soreceive() expects the following conventions to be
+ * observed when placing information in the receive buffer:
+ *
+ * 1. If the protocol requires each message be preceded by the sender's
+ *    name, then a record containing that name must be present before
+ *    any associated data (mbuf's must be of type MT_SONAME).
+ * 2. If the protocol supports the exchange of ``access rights'' (really
+ *    just additional data associated with the message), and there are
+ *    ``rights'' to be received, then a record containing this data
+ *    should be present (mbuf's must be of type MT_RIGHTS).
+ * 3. If a name or rights record exists, then it must be followed by
+ *    a data record, perhaps of zero length.
+ *
+ * Before using a new socket structure it is first necessary to reserve
+ * buffer space to the socket, by calling sbreserve().  This should commit
+ * some of the available buffer space in the system buffer pool for the
+ * socket (currently, it does nothing but enforce limits).  The space
+ * should be released by calling sbrelease() when the socket is destroyed.
+ */
+
+soreserve(so, sndcc, rcvcc)
+       register struct socket *so;
+       u_long sndcc, rcvcc;
+{
+
+       if (sbreserve(&so->so_snd, sndcc) == 0)
+               goto bad;
+       if (sbreserve(&so->so_rcv, rcvcc) == 0)
+               goto bad2;
+       if (so->so_rcv.sb_lowat == 0)
+               so->so_rcv.sb_lowat = 1;
+       if (so->so_snd.sb_lowat == 0)
+               so->so_snd.sb_lowat = MCLBYTES;
+       if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
+               so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
+       return (0);
+bad2:
+       sbrelease(&so->so_snd);
+bad:
+       return (ENOBUFS);
+}
+
+/*
+ * Allot mbufs to a sockbuf.
+ * Attempt to scale mbmax so that mbcnt doesn't become limiting
+ * if buffering efficiency is near the normal case.
+ */
+sbreserve(sb, cc)
+       struct sockbuf *sb;
+       u_long cc;
+{
+
+       if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES))
+               return (0);
+       sb->sb_hiwat = cc;
+       sb->sb_mbmax = min(cc * 2, sb_max);
+       if (sb->sb_lowat > sb->sb_hiwat)
+               sb->sb_lowat = sb->sb_hiwat;
+       return (1);
+}
+
+/*
+ * Free mbufs held by a socket, and reserved mbuf space.
+ */
+sbrelease(sb)
+       struct sockbuf *sb;
+{
+
+       sbflush(sb);
+       sb->sb_hiwat = sb->sb_mbmax = 0;
+}
+
+/*
+ * Routines to add and remove
+ * data from an mbuf queue.
+ *
+ * The routines sbappend() or sbappendrecord() are normally called to
+ * append new mbufs to a socket buffer, after checking that adequate
+ * space is available, comparing the function sbspace() with the amount
+ * of data to be added.  sbappendrecord() differs from sbappend() in
+ * that data supplied is treated as the beginning of a new record.
+ * To place a sender's address, optional access rights, and data in a
+ * socket receive buffer, sbappendaddr() should be used.  To place
+ * access rights and data in a socket receive buffer, sbappendrights()
+ * should be used.  In either case, the new data begins a new record.
+ * Note that unlike sbappend() and sbappendrecord(), these routines check
+ * for the caller that there will be enough space to store the data.
+ * Each fails if there is not enough space, or if it cannot find mbufs
+ * to store additional information in.
+ *
+ * Reliable protocols may use the socket send buffer to hold data
+ * awaiting acknowledgement.  Data is normally copied from a socket
+ * send buffer in a protocol with m_copy for output to a peer,
+ * and then removing the data from the socket buffer with sbdrop()
+ * or sbdroprecord() when the data is acknowledged by the peer.
+ */
+
+/*
+ * Append mbuf chain m to the last record in the
+ * socket buffer sb.  The additional space associated
+ * the mbuf chain is recorded in sb.  Empty mbufs are
+ * discarded and mbufs are compacted where possible.
+ */
+sbappend(sb, m)
+       struct sockbuf *sb;
+       struct mbuf *m;
+{
+       register struct mbuf *n;
+
+       if (m == 0)
+               return;
+       if (n = sb->sb_mb) {
+               while (n->m_nextpkt)
+                       n = n->m_nextpkt;
+               do {
+                       if (n->m_flags & M_EOR) {
+                               sbappendrecord(sb, m); /* XXXXXX!!!! */
+                               return;
+                       }
+               } while (n->m_next && (n = n->m_next));
+       }
+       sbcompress(sb, m, n);
+}
+
+#ifdef SOCKBUF_DEBUG
+sbcheck(sb)
+       register struct sockbuf *sb;
+{
+       register struct mbuf *m;
+       register int len = 0, mbcnt = 0;
+
+       for (m = sb->sb_mb; m; m = m->m_next) {
+               len += m->m_len;
+               mbcnt += MSIZE;
+               if (m->m_flags & M_EXT)
+                       mbcnt += m->m_ext.ext_size;
+               if (m->m_nextpkt)
+                       panic("sbcheck nextpkt");
+       }
+       if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
+               printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc,
+                   mbcnt, sb->sb_mbcnt);
+               panic("sbcheck");
+       }
+}
+#endif
+
+/*
+ * As above, except the mbuf chain
+ * begins a new record.
+ */
+sbappendrecord(sb, m0)
+       register struct sockbuf *sb;
+       register struct mbuf *m0;
+{
+       register struct mbuf *m;
+
+       if (m0 == 0)
+               return;
+       if (m = sb->sb_mb)
+               while (m->m_nextpkt)
+                       m = m->m_nextpkt;
+       /*
+        * Put the first mbuf on the queue.
+        * Note this permits zero length records.
+        */
+       sballoc(sb, m0);
+       if (m)
+               m->m_nextpkt = m0;
+       else
+               sb->sb_mb = m0;
+       m = m0->m_next;
+       m0->m_next = 0;
+       if (m && (m0->m_flags & M_EOR)) {
+               m0->m_flags &= ~M_EOR;
+               m->m_flags |= M_EOR;
+       }
+       sbcompress(sb, m, m0);
+}
+
+/*
+ * As above except that OOB data
+ * is inserted at the beginning of the sockbuf,
+ * but after any other OOB data.
+ */
+sbinsertoob(sb, m0)
+       register struct sockbuf *sb;
+       register struct mbuf *m0;
+{
+       register struct mbuf *m;
+       register struct mbuf **mp;
+
+       if (m0 == 0)
+               return;
+       for (mp = &sb->sb_mb; m = *mp; mp = &((*mp)->m_nextpkt)) {
+           again:
+               switch (m->m_type) {
+
+               case MT_OOBDATA:
+                       continue;               /* WANT next train */
+
+               case MT_CONTROL:
+                       if (m = m->m_next)
+                               goto again;     /* inspect THIS train further */
+               }
+               break;
+       }
+       /*
+        * Put the first mbuf on the queue.
+        * Note this permits zero length records.
+        */
+       sballoc(sb, m0);
+       m0->m_nextpkt = *mp;
+       *mp = m0;
+       m = m0->m_next;
+       m0->m_next = 0;
+       if (m && (m0->m_flags & M_EOR)) {
+               m0->m_flags &= ~M_EOR;
+               m->m_flags |= M_EOR;
+       }
+       sbcompress(sb, m, m0);
+}
+
+/*
+ * Append address and data, and optionally, control (ancillary) data
+ * to the receive queue of a socket.  If present,
+ * m0 must include a packet header with total length.
+ * Returns 0 if no space in sockbuf or insufficient mbufs.
+ */
+sbappendaddr(sb, asa, m0, control)
+       register struct sockbuf *sb;
+       struct sockaddr *asa;
+       struct mbuf *m0, *control;
+{
+       register struct mbuf *m, *n;
+       int space = asa->sa_len;
+
+if (m0 && (m0->m_flags & M_PKTHDR) == 0)
+panic("sbappendaddr");
+       if (m0)
+               space += m0->m_pkthdr.len;
+       for (n = control; n; n = n->m_next) {
+               space += n->m_len;
+               if (n->m_next == 0)     /* keep pointer to last control buf */
+                       break;
+       }
+       if (space > sbspace(sb))
+               return (0);
+       if (asa->sa_len > MLEN)
+               return (0);
+       MGET(m, M_DONTWAIT, MT_SONAME);
+       if (m == 0)
+               return (0);
+       m->m_len = asa->sa_len;
+       bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len);
+       if (n)
+               n->m_next = m0;         /* concatenate data to control */
+       else
+               control = m0;
+       m->m_next = control;
+       for (n = m; n; n = n->m_next)
+               sballoc(sb, n);
+       if (n = sb->sb_mb) {
+               while (n->m_nextpkt)
+                       n = n->m_nextpkt;
+               n->m_nextpkt = m;
+       } else
+               sb->sb_mb = m;
+       return (1);
+}
+
+sbappendcontrol(sb, m0, control)
+       struct sockbuf *sb;
+       struct mbuf *control, *m0;
+{
+       register struct mbuf *m, *n;
+       int space = 0;
+
+       if (control == 0)
+               panic("sbappendcontrol");
+       for (m = control; ; m = m->m_next) {
+               space += m->m_len;
+               if (m->m_next == 0)
+                       break;
+       }
+       n = m;                  /* save pointer to last control buffer */
+       for (m = m0; m; m = m->m_next)
+               space += m->m_len;
+       if (space > sbspace(sb))
+               return (0);
+       n->m_next = m0;                 /* concatenate data to control */
+       for (m = control; m; m = m->m_next)
+               sballoc(sb, m);
+       if (n = sb->sb_mb) {
+               while (n->m_nextpkt)
+                       n = n->m_nextpkt;
+               n->m_nextpkt = control;
+       } else
+               sb->sb_mb = control;
+       return (1);
+}
+
+/*
+ * Compress mbuf chain m into the socket
+ * buffer sb following mbuf n.  If n
+ * is null, the buffer is presumed empty.
+ */
+sbcompress(sb, m, n)
+       register struct sockbuf *sb;
+       register struct mbuf *m, *n;
+{
+       register int eor = 0;
+       register struct mbuf *o;
+
+       while (m) {
+               eor |= m->m_flags & M_EOR;
+               if (m->m_len == 0 &&
+                   (eor == 0 ||
+                    (((o = m->m_next) || (o = n)) &&
+                     o->m_type == m->m_type))) {
+                       m = m_free(m);
+                       continue;
+               }
+               if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 &&
+                   (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] &&
+                   n->m_type == m->m_type) {
+                       bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
+                           (unsigned)m->m_len);
+                       n->m_len += m->m_len;
+                       sb->sb_cc += m->m_len;
+                       m = m_free(m);
+                       continue;
+               }
+               if (n)
+                       n->m_next = m;
+               else
+                       sb->sb_mb = m;
+               sballoc(sb, m);
+               n = m;
+               m->m_flags &= ~M_EOR;
+               m = m->m_next;
+               n->m_next = 0;
+       }
+       if (eor) {
+               if (n)
+                       n->m_flags |= eor;
+               else
+                       printf("semi-panic: sbcompress\n");
+       }
+}
+
+/*
+ * Free all mbufs in a sockbuf.
+ * Check that all resources are reclaimed.
+ */
+sbflush(sb)
+       register struct sockbuf *sb;
+{
+
+       if (sb->sb_flags & SB_LOCK)
+               panic("sbflush");
+       while (sb->sb_mbcnt)
+               sbdrop(sb, (int)sb->sb_cc);
+       if (sb->sb_cc || sb->sb_mb)
+               panic("sbflush 2");
+}
+
+/*
+ * Drop data from (the front of) a sockbuf.
+ */
+sbdrop(sb, len)
+       register struct sockbuf *sb;
+       register int len;
+{
+       register struct mbuf *m, *mn;
+       struct mbuf *next;
+
+       next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
+       while (len > 0) {
+               if (m == 0) {
+                       if (next == 0)
+                               panic("sbdrop");
+                       m = next;
+                       next = m->m_nextpkt;
+                       continue;
+               }
+               if (m->m_len > len) {
+                       m->m_len -= len;
+                       m->m_data += len;
+                       sb->sb_cc -= len;
+                       break;
+               }
+               len -= m->m_len;
+               sbfree(sb, m);
+               MFREE(m, mn);
+               m = mn;
+       }
+       while (m && m->m_len == 0) {
+               sbfree(sb, m);
+               MFREE(m, mn);
+               m = mn;
+       }
+       if (m) {
+               sb->sb_mb = m;
+               m->m_nextpkt = next;
+       } else
+               sb->sb_mb = next;
+}
+
+/*
+ * Drop a record off the front of a sockbuf
+ * and move the next record to the front.
+ */
+sbdroprecord(sb)
+       register struct sockbuf *sb;
+{
+       register struct mbuf *m, *mn;
+
+       m = sb->sb_mb;
+       if (m) {
+               sb->sb_mb = m->m_nextpkt;
+               do {
+                       sbfree(sb, m);
+                       MFREE(m, mn);
+               } while (m = mn);
+       }
+}
diff --git a/usr/src/sys.386bsd/kern/vfs_cache.c b/usr/src/sys.386bsd/kern/vfs_cache.c
new file mode 100644 (file)
index 0000000..d24de73
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vfs_cache.c 7.8 (Berkeley) 2/28/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "mount.h"
+#include "vnode.h"
+#include "namei.h"
+#include "errno.h"
+#include "malloc.h"
+
+/*
+ * Name caching works as follows:
+ *
+ * Names found by directory scans are retained in a cache
+ * for future reference.  It is managed LRU, so frequently
+ * used names will hang around.  Cache is indexed by hash value
+ * obtained from (vp, name) where vp refers to the directory
+ * containing name.
+ *
+ * For simplicity (and economy of storage), names longer than
+ * a maximum length of NCHNAMLEN are not cached; they occur
+ * infrequently in any case, and are almost never of interest.
+ *
+ * Upon reaching the last segment of a path, if the reference
+ * is for DELETE, or NOCACHE is set (rewrite), and the
+ * name is located in the cache, it will be dropped.
+ */
+
+/*
+ * Structures associated with name cacheing.
+ */
+union nchash {
+       union   nchash *nch_head[2];
+       struct  namecache *nch_chain[2];
+} *nchashtbl;
+#define        nch_forw        nch_chain[0]
+#define        nch_back        nch_chain[1]
+
+u_long nchash;                         /* size of hash table - 1 */
+long   numcache;                       /* number of cache entries allocated */
+struct namecache *nchhead, **nchtail;  /* LRU chain pointers */
+struct nchstats nchstats;              /* cache effectiveness statistics */
+
+int doingcache = 1;                    /* 1 => enable the cache */
+
+/*
+ * Look for a the name in the cache. We don't do this
+ * if the segment name is long, simply so the cache can avoid
+ * holding long names (which would either waste space, or
+ * add greatly to the complexity).
+ *
+ * Lookup is called with ni_dvp pointing to the directory to search,
+ * ni_ptr pointing to the name of the entry being sought, ni_namelen
+ * tells the length of the name, and ni_hash contains a hash of
+ * the name. If the lookup succeeds, the vnode is returned in ni_vp
+ * and a status of -1 is returned. If the lookup determines that
+ * the name does not exist (negative cacheing), a status of ENOENT
+ * is returned. If the lookup fails, a status of zero is returned.
+ */
+cache_lookup(ndp)
+       register struct nameidata *ndp;
+{
+       register struct vnode *dvp;
+       register struct namecache *ncp;
+       union nchash *nhp;
+
+       if (!doingcache)
+               return (0);
+       if (ndp->ni_namelen > NCHNAMLEN) {
+               nchstats.ncs_long++;
+               ndp->ni_makeentry = 0;
+               return (0);
+       }
+       dvp = ndp->ni_dvp;
+       nhp = &nchashtbl[ndp->ni_hash & nchash];
+       for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
+           ncp = ncp->nc_forw) {
+               if (ncp->nc_dvp == dvp &&
+                   ncp->nc_dvpid == dvp->v_id &&
+                   ncp->nc_nlen == ndp->ni_namelen &&
+                   !bcmp(ncp->nc_name, ndp->ni_ptr, (unsigned)ncp->nc_nlen))
+                       break;
+       }
+       if (ncp == (struct namecache *)nhp) {
+               nchstats.ncs_miss++;
+               return (0);
+       }
+       if (!ndp->ni_makeentry) {
+               nchstats.ncs_badhits++;
+       } else if (ncp->nc_vp == NULL) {
+               if ((ndp->ni_nameiop & OPMASK) != CREATE) {
+                       nchstats.ncs_neghits++;
+                       /*
+                        * Move this slot to end of LRU chain,
+                        * if not already there.
+                        */
+                       if (ncp->nc_nxt) {
+                               /* remove from LRU chain */
+                               *ncp->nc_prev = ncp->nc_nxt;
+                               ncp->nc_nxt->nc_prev = ncp->nc_prev;
+                               /* and replace at end of it */
+                               ncp->nc_nxt = NULL;
+                               ncp->nc_prev = nchtail;
+                               *nchtail = ncp;
+                               nchtail = &ncp->nc_nxt;
+                       }
+                       return (ENOENT);
+               }
+       } else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
+               nchstats.ncs_falsehits++;
+       } else {
+               nchstats.ncs_goodhits++;
+               /*
+                * move this slot to end of LRU chain, if not already there
+                */
+               if (ncp->nc_nxt) {
+                       /* remove from LRU chain */
+                       *ncp->nc_prev = ncp->nc_nxt;
+                       ncp->nc_nxt->nc_prev = ncp->nc_prev;
+                       /* and replace at end of it */
+                       ncp->nc_nxt = NULL;
+                       ncp->nc_prev = nchtail;
+                       *nchtail = ncp;
+                       nchtail = &ncp->nc_nxt;
+               }
+               ndp->ni_vp = ncp->nc_vp;
+               return (-1);
+       }
+
+       /*
+        * Last component and we are renaming or deleting,
+        * the cache entry is invalid, or otherwise don't
+        * want cache entry to exist.
+        */
+       /* remove from LRU chain */
+       *ncp->nc_prev = ncp->nc_nxt;
+       if (ncp->nc_nxt)
+               ncp->nc_nxt->nc_prev = ncp->nc_prev;
+       else
+               nchtail = ncp->nc_prev;
+       /* remove from hash chain */
+       remque(ncp);
+       /* insert at head of LRU list (first to grab) */
+       ncp->nc_nxt = nchhead;
+       ncp->nc_prev = &nchhead;
+       nchhead->nc_prev = &ncp->nc_nxt;
+       nchhead = ncp;
+       /* and make a dummy hash chain */
+       ncp->nc_forw = ncp;
+       ncp->nc_back = ncp;
+       return (0);
+}
+
+/*
+ * Add an entry to the cache
+ */
+cache_enter(ndp)
+       register struct nameidata *ndp;
+{
+       register struct namecache *ncp;
+       union nchash *nhp;
+
+       if (!doingcache)
+               return;
+       /*
+        * Free the cache slot at head of lru chain.
+        */
+       if (numcache < desiredvnodes) {
+               ncp = (struct namecache *)
+                       malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
+               bzero((char *)ncp, sizeof *ncp);
+               numcache++;
+       } else if (ncp = nchhead) {
+               /* remove from lru chain */
+               *ncp->nc_prev = ncp->nc_nxt;
+               if (ncp->nc_nxt)
+                       ncp->nc_nxt->nc_prev = ncp->nc_prev;
+               else
+                       nchtail = ncp->nc_prev;
+               /* remove from old hash chain */
+               remque(ncp);
+       } else
+               return;
+       /* grab the vnode we just found */
+       ncp->nc_vp = ndp->ni_vp;
+       if (ndp->ni_vp)
+               ncp->nc_vpid = ndp->ni_vp->v_id;
+       else
+               ncp->nc_vpid = 0;
+       /* fill in cache info */
+       ncp->nc_dvp = ndp->ni_dvp;
+       ncp->nc_dvpid = ndp->ni_dvp->v_id;
+       ncp->nc_nlen = ndp->ni_namelen;
+       bcopy(ndp->ni_ptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
+       /* link at end of lru chain */
+       ncp->nc_nxt = NULL;
+       ncp->nc_prev = nchtail;
+       *nchtail = ncp;
+       nchtail = &ncp->nc_nxt;
+       /* and insert on hash chain */
+       nhp = &nchashtbl[ndp->ni_hash & nchash];
+       insque(ncp, nhp);
+}
+
+/*
+ * Name cache initialization, from vfs_init() when we are booting
+ */
+nchinit()
+{
+       register union nchash *nchp;
+       long nchashsize;
+
+       nchhead = 0;
+       nchtail = &nchhead;
+       nchashsize = roundup((desiredvnodes + 1) * sizeof *nchp / 2,
+               NBPG * CLSIZE);
+       nchashtbl = (union nchash *)malloc((u_long)nchashsize,
+           M_CACHE, M_WAITOK);
+       for (nchash = 1; nchash <= nchashsize / sizeof *nchp; nchash <<= 1)
+               /* void */;
+       nchash = (nchash >> 1) - 1;
+       for (nchp = &nchashtbl[nchash]; nchp >= nchashtbl; nchp--) {
+               nchp->nch_head[0] = nchp;
+               nchp->nch_head[1] = nchp;
+       }
+}
+
+/*
+ * Cache flush, a particular vnode; called when a vnode is renamed to
+ * hide entries that would now be invalid
+ */
+cache_purge(vp)
+       struct vnode *vp;
+{
+       union nchash *nhp;
+       struct namecache *ncp;
+
+       vp->v_id = ++nextvnodeid;
+       if (nextvnodeid != 0)
+               return;
+       for (nhp = &nchashtbl[nchash]; nhp >= nchashtbl; nhp--) {
+               for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
+                   ncp = ncp->nc_forw) {
+                       ncp->nc_vpid = 0;
+                       ncp->nc_dvpid = 0;
+               }
+       }
+       vp->v_id = ++nextvnodeid;
+}
+
+/*
+ * Cache flush, a whole filesystem; called when filesys is umounted to
+ * remove entries that would now be invalid
+ *
+ * The line "nxtcp = nchhead" near the end is to avoid potential problems
+ * if the cache lru chain is modified while we are dumping the
+ * inode.  This makes the algorithm O(n^2), but do you think I care?
+ */
+cache_purgevfs(mp)
+       struct mount *mp;
+{
+       register struct namecache *ncp, *nxtcp;
+
+       for (ncp = nchhead; ncp; ncp = nxtcp) {
+               nxtcp = ncp->nc_nxt;
+               if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp)
+                       continue;
+               /* free the resources we had */
+               ncp->nc_vp = NULL;
+               ncp->nc_dvp = NULL;
+               remque(ncp);            /* remove entry from its hash chain */
+               ncp->nc_forw = ncp;     /* and make a dummy one */
+               ncp->nc_back = ncp;
+               /* delete this entry from LRU chain */
+               *ncp->nc_prev = nxtcp;
+               if (nxtcp)
+                       nxtcp->nc_prev = ncp->nc_prev;
+               else
+                       nchtail = ncp->nc_prev;
+               /* cause rescan of list, it may have altered */
+               nxtcp = nchhead;
+               /* put the now-free entry at head of LRU */
+               ncp->nc_nxt = nxtcp;
+               ncp->nc_prev = &nchhead;
+               nxtcp->nc_prev = &ncp->nc_nxt;
+               nchhead = ncp;
+       }
+}
diff --git a/usr/src/sys.386bsd/kern/vfs_lookup.c b/usr/src/sys.386bsd/kern/vfs_lookup.c
new file mode 100644 (file)
index 0000000..9d7668c
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vfs_lookup.c        7.32 (Berkeley) 5/21/91
+ */
+
+#include "param.h"
+#include "syslimits.h"
+#include "time.h"
+#include "namei.h"
+#include "vnode.h"
+#include "mount.h"
+#include "errno.h"
+#include "malloc.h"
+#include "filedesc.h"
+#include "proc.h"
+
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+/*
+ * Convert a pathname into a pointer to a locked inode.
+ *
+ * The FOLLOW flag is set when symbolic links are to be followed
+ * when they occur at the end of the name translation process.
+ * Symbolic links are always followed for all other pathname
+ * components other than the last.
+ *
+ * The segflg defines whether the name is to be copied from user
+ * space or kernel space.
+ *
+ * Overall outline of namei:
+ *
+ *     copy in name
+ *     get starting directory
+ *     while (!done && !error) {
+ *             call lookup to search path.
+ *             if symbolic link, massage name in buffer and continue
+ *     }
+ */
+namei(ndp, p)
+       register struct nameidata *ndp;
+       struct proc *p;
+{
+       register struct filedesc *fdp;  /* pointer to file descriptor state */
+       register char *cp;              /* pointer into pathname argument */
+       register struct vnode *dp;      /* the directory we are searching */
+       struct iovec aiov;              /* uio for reading symbolic links */
+       struct uio auio;
+       int error, linklen;
+
+       ndp->ni_cred = p->p_ucred;
+       fdp = p->p_fd;
+
+       /*
+        * Get a buffer for the name to be translated, and copy the
+        * name into the buffer.
+        */
+       if ((ndp->ni_nameiop & HASBUF) == 0)
+               MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
+       if (ndp->ni_segflg == UIO_SYSSPACE)
+               error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
+                           MAXPATHLEN, &ndp->ni_pathlen);
+       else
+               error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
+                           MAXPATHLEN, &ndp->ni_pathlen);
+       if (error) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               ndp->ni_vp = NULL;
+               return (error);
+       }
+       ndp->ni_loopcnt = 0;
+#ifdef KTRACE
+       if (KTRPOINT(p, KTR_NAMEI))
+               ktrnamei(p->p_tracep, ndp->ni_pnbuf);
+#endif
+
+       /*
+        * Get starting point for the translation.
+        */
+       if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
+               ndp->ni_rootdir = rootdir;
+       dp = fdp->fd_cdir;
+       VREF(dp);
+       for (;;) {
+               /*
+                * Check if root directory should replace current directory.
+                * Done at start of translation and after symbolic link.
+                */
+               ndp->ni_ptr = ndp->ni_pnbuf;
+               if (*ndp->ni_ptr == '/') {
+                       vrele(dp);
+                       while (*ndp->ni_ptr == '/') {
+                               ndp->ni_ptr++;
+                               ndp->ni_pathlen--;
+                       }
+                       dp = ndp->ni_rootdir;
+                       VREF(dp);
+               }
+               ndp->ni_startdir = dp;
+               if (error = lookup(ndp, p)) {
+                       FREE(ndp->ni_pnbuf, M_NAMEI);
+                       return (error);
+               }
+               /*
+                * Check for symbolic link
+                */
+               if (ndp->ni_more == 0) {
+                       if ((ndp->ni_nameiop & (SAVENAME | SAVESTART)) == 0)
+                               FREE(ndp->ni_pnbuf, M_NAMEI);
+                       else
+                               ndp->ni_nameiop |= HASBUF;
+                       return (0);
+               }
+               if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
+                       VOP_UNLOCK(ndp->ni_dvp);
+               if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
+                       error = ELOOP;
+                       break;
+               }
+               if (ndp->ni_pathlen > 1)
+                       MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
+               else
+                       cp = ndp->ni_pnbuf;
+               aiov.iov_base = cp;
+               aiov.iov_len = MAXPATHLEN;
+               auio.uio_iov = &aiov;
+               auio.uio_iovcnt = 1;
+               auio.uio_offset = 0;
+               auio.uio_rw = UIO_READ;
+               auio.uio_segflg = UIO_SYSSPACE;
+               auio.uio_procp = (struct proc *)0;
+               auio.uio_resid = MAXPATHLEN;
+               if (error = VOP_READLINK(ndp->ni_vp, &auio, p->p_ucred)) {
+                       if (ndp->ni_pathlen > 1)
+                               free(cp, M_NAMEI);
+                       break;
+               }
+               linklen = MAXPATHLEN - auio.uio_resid;
+               if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
+                       if (ndp->ni_pathlen > 1)
+                               free(cp, M_NAMEI);
+                       error = ENAMETOOLONG;
+                       break;
+               }
+               if (ndp->ni_pathlen > 1) {
+                       bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
+                       FREE(ndp->ni_pnbuf, M_NAMEI);
+                       ndp->ni_pnbuf = cp;
+               } else
+                       ndp->ni_pnbuf[linklen] = '\0';
+               ndp->ni_pathlen += linklen;
+               vput(ndp->ni_vp);
+               dp = ndp->ni_dvp;
+       }
+       FREE(ndp->ni_pnbuf, M_NAMEI);
+       vrele(ndp->ni_dvp);
+       vput(ndp->ni_vp);
+       ndp->ni_vp = NULL;
+       return (error);
+}
+
+/*
+ * Search a pathname.
+ * This is a very central and rather complicated routine.
+ *
+ * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
+ * The starting directory is taken from ni_startdir. The pathname is
+ * descended until done, or a symbolic link is encountered. The variable
+ * ni_more is clear if the path is completed; it is set to one if a
+ * symbolic link needing interpretation is encountered.
+ *
+ * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
+ * whether the name is to be looked up, created, renamed, or deleted.
+ * When CREATE, RENAME, or DELETE is specified, information usable in
+ * creating, renaming, or deleting a directory entry may be calculated.
+ * If flag has LOCKPARENT or'ed into it, the parent directory is returned
+ * locked. If flag has WANTPARENT or'ed into it, the parent directory is
+ * returned unlocked. Otherwise the parent directory is not returned. If
+ * the target of the pathname exists and LOCKLEAF is or'ed into the flag
+ * the target is returned locked, otherwise it is returned unlocked.
+ * When creating or renaming and LOCKPARENT is specified, the target may not
+ * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
+ * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
+ * 
+ * Overall outline of lookup:
+ *
+ * dirloop:
+ *     identify next component of name at ndp->ni_ptr
+ *     handle degenerate case where name is null string
+ *     if .. and crossing mount points and on mounted filesys, find parent
+ *     call VOP_LOOKUP routine for next component name
+ *         directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
+ *         component vnode returned in ni_vp (if it exists), locked.
+ *     if result vnode is mounted on and crossing mount points,
+ *         find mounted on vnode
+ *     if more components of name, do next level at dirloop
+ *     return the answer in ni_vp, locked if LOCKLEAF set
+ *         if LOCKPARENT set, return locked parent in ni_dvp
+ *         if WANTPARENT set, return unlocked parent in ni_dvp
+ */
+lookup(ndp, p)
+       register struct nameidata *ndp;
+       struct proc *p;
+{
+       register char *cp;              /* pointer into pathname argument */
+       register struct vnode *dp = 0;  /* the directory we are searching */
+       struct vnode *tdp;              /* saved dp */
+       struct mount *mp;               /* mount table entry */
+       int docache;                    /* == 0 do not cache last component */
+       int flag;                       /* LOOKUP, CREATE, RENAME or DELETE */
+       int wantparent;                 /* 1 => wantparent or lockparent flag */
+       int rdonly;                     /* mounted read-only flag bit(s) */
+       int error = 0;
+
+       /*
+        * Setup: break out flag bits into variables.
+        */
+       flag = ndp->ni_nameiop & OPMASK;
+       wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
+       docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
+       if (flag == DELETE || (wantparent && flag != CREATE))
+               docache = 0;
+       rdonly = MNT_RDONLY;
+       if (ndp->ni_nameiop & REMOTE)
+               rdonly |= MNT_EXRDONLY;
+       ndp->ni_dvp = NULL;
+       ndp->ni_more = 0;
+       dp = ndp->ni_startdir;
+       ndp->ni_startdir = NULLVP;
+       VOP_LOCK(dp);
+
+dirloop:
+       /*
+        * Search a new directory.
+        *
+        * The ni_hash value is for use by vfs_cache.
+        * The last component of the filename is left accessible via
+        * ndp->ptr for callers that need the name. Callers needing
+        * the name set the SAVENAME flag. When done, they assume
+        * responsibility for freeing the pathname buffer.
+        */
+       ndp->ni_hash = 0;
+       for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++)
+               ndp->ni_hash += (unsigned char)*cp;
+       ndp->ni_namelen = cp - ndp->ni_ptr;
+       if (ndp->ni_namelen >= NAME_MAX) {
+               error = ENAMETOOLONG;
+               goto bad;
+       }
+#ifdef NAMEI_DIAGNOSTIC
+       { char c = *cp;
+       *cp = '\0';
+       printf("{%s}: ", ndp->ni_ptr);
+       *cp = c; }
+#endif
+       ndp->ni_pathlen -= ndp->ni_namelen;
+       ndp->ni_next = cp;
+       ndp->ni_makeentry = 1;
+       if (*cp == '\0' && docache == 0)
+               ndp->ni_makeentry = 0;
+       ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
+               ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.');
+
+       /*
+        * Check for degenerate name (e.g. / or "")
+        * which is a way of talking about a directory,
+        * e.g. like "/." or ".".
+        */
+       if (ndp->ni_ptr[0] == '\0') {
+               if (flag != LOOKUP || wantparent) {
+                       error = EISDIR;
+                       goto bad;
+               }
+               if (dp->v_type != VDIR) {
+                       error = ENOTDIR;
+                       goto bad;
+               }
+               if (!(ndp->ni_nameiop & LOCKLEAF))
+                       VOP_UNLOCK(dp);
+               ndp->ni_vp = dp;
+               if (ndp->ni_nameiop & SAVESTART)
+                       panic("lookup: SAVESTART");
+               return (0);
+       }
+
+       /*
+        * Handle "..": two special cases.
+        * 1. If at root directory (e.g. after chroot)
+        *    then ignore it so can't get out.
+        * 2. If this vnode is the root of a mounted
+        *    filesystem, then replace it with the
+        *    vnode which was mounted on so we take the
+        *    .. in the other file system.
+        */
+       if (ndp->ni_isdotdot) {
+               for (;;) {
+                       if (dp == ndp->ni_rootdir) {
+                               ndp->ni_dvp = dp;
+                               ndp->ni_vp = dp;
+                               VREF(dp);
+                               goto nextname;
+                       }
+                       if ((dp->v_flag & VROOT) == 0 ||
+                           (ndp->ni_nameiop & NOCROSSMOUNT))
+                               break;
+                       tdp = dp;
+                       dp = dp->v_mount->mnt_vnodecovered;
+                       vput(tdp);
+                       VREF(dp);
+                       VOP_LOCK(dp);
+               }
+       }
+
+       /*
+        * We now have a segment name to search for, and a directory to search.
+        */
+       if (error = VOP_LOOKUP(dp, ndp, p)) {
+#ifdef DIAGNOSTIC
+               if (ndp->ni_vp != NULL)
+                       panic("leaf should be empty");
+#endif
+#ifdef NAMEI_DIAGNOSTIC
+               printf("not found\n");
+#endif
+               if (flag == LOOKUP || flag == DELETE ||
+                   error != ENOENT || *cp != 0)
+                       goto bad;
+               /*
+                * If creating and at end of pathname, then can consider
+                * allowing file to be created.
+                */
+               if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
+                       error = EROFS;
+                       goto bad;
+               }
+               /*
+                * We return with ni_vp NULL to indicate that the entry
+                * doesn't currently exist, leaving a pointer to the
+                * (possibly locked) directory inode in ndp->ni_dvp.
+                */
+               if (ndp->ni_nameiop & SAVESTART) {
+                       ndp->ni_startdir = ndp->ni_dvp;
+                       VREF(ndp->ni_startdir);
+               }
+               return (0);
+       }
+#ifdef NAMEI_DIAGNOSTIC
+       printf("found\n");
+#endif
+
+       dp = ndp->ni_vp;
+       /*
+        * Check for symbolic link
+        */
+       if ((dp->v_type == VLNK) &&
+           ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
+               ndp->ni_more = 1;
+               return (0);
+       }
+
+       /*
+        * Check to see if the vnode has been mounted on;
+        * if so find the root of the mounted file system.
+        */
+mntloop:
+       while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
+              (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
+               while(mp->mnt_flag & MNT_MLOCK) {
+                       mp->mnt_flag |= MNT_MWAIT;
+                       sleep((caddr_t)mp, PVFS);
+                       goto mntloop;
+               }
+               if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
+                       goto bad2;
+               vput(dp);
+               ndp->ni_vp = dp = tdp;
+       }
+
+nextname:
+       /*
+        * Not a symbolic link.  If more pathname,
+        * continue at next component, else return.
+        */
+       if (*ndp->ni_next == '/') {
+               ndp->ni_ptr = ndp->ni_next;
+               while (*ndp->ni_ptr == '/') {
+                       ndp->ni_ptr++;
+                       ndp->ni_pathlen--;
+               }
+               vrele(ndp->ni_dvp);
+               goto dirloop;
+       }
+       /*
+        * Check for read-only file systems.
+        */
+       if (flag == DELETE || flag == RENAME) {
+               /*
+                * Disallow directory write attempts on read-only
+                * file systems.
+                */
+               if ((dp->v_mount->mnt_flag & rdonly) ||
+                   (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
+                       error = EROFS;
+                       goto bad2;
+               }
+       }
+       if (ndp->ni_nameiop & SAVESTART) {
+               ndp->ni_startdir = ndp->ni_dvp;
+               VREF(ndp->ni_startdir);
+       }
+       if (!wantparent)
+               vrele(ndp->ni_dvp);
+       if ((ndp->ni_nameiop & LOCKLEAF) == 0)
+               VOP_UNLOCK(dp);
+       return (0);
+
+bad2:
+       if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0')
+               VOP_UNLOCK(ndp->ni_dvp);
+       vrele(ndp->ni_dvp);
+bad:
+       vput(dp);
+       ndp->ni_vp = NULL;
+       return (error);
+}
diff --git a/usr/src/sys.386bsd/kern/vfs_subr.c b/usr/src/sys.386bsd/kern/vfs_subr.c
new file mode 100644 (file)
index 0000000..98c5a63
--- /dev/null
@@ -0,0 +1,1185 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vfs_subr.c  7.60 (Berkeley) 6/21/91
+ */
+
+/*
+ * External virtual filesystem routines
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "mount.h"
+#include "time.h"
+#include "vnode.h"
+#include "specdev.h"
+#include "namei.h"
+#include "ucred.h"
+#include "buf.h"
+#include "errno.h"
+#include "malloc.h"
+
+/*
+ * Remove a mount point from the list of mounted filesystems.
+ * Unmount of the root is illegal.
+ */
+void
+vfs_remove(mp)
+       register struct mount *mp;
+{
+
+       if (mp == rootfs)
+               panic("vfs_remove: unmounting root");
+       mp->mnt_prev->mnt_next = mp->mnt_next;
+       mp->mnt_next->mnt_prev = mp->mnt_prev;
+       mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
+       vfs_unlock(mp);
+}
+
+/*
+ * Lock a filesystem.
+ * Used to prevent access to it while mounting and unmounting.
+ */
+vfs_lock(mp)
+       register struct mount *mp;
+{
+
+       while(mp->mnt_flag & MNT_MLOCK) {
+               mp->mnt_flag |= MNT_MWAIT;
+               sleep((caddr_t)mp, PVFS);
+       }
+       mp->mnt_flag |= MNT_MLOCK;
+       return (0);
+}
+
+/*
+ * Unlock a locked filesystem.
+ * Panic if filesystem is not locked.
+ */
+void
+vfs_unlock(mp)
+       register struct mount *mp;
+{
+
+       if ((mp->mnt_flag & MNT_MLOCK) == 0)
+               panic("vfs_unlock: not locked");
+       mp->mnt_flag &= ~MNT_MLOCK;
+       if (mp->mnt_flag & MNT_MWAIT) {
+               mp->mnt_flag &= ~MNT_MWAIT;
+               wakeup((caddr_t)mp);
+       }
+}
+
+/*
+ * Mark a mount point as busy.
+ * Used to synchronize access and to delay unmounting.
+ */
+vfs_busy(mp)
+       register struct mount *mp;
+{
+
+       while(mp->mnt_flag & MNT_MPBUSY) {
+               mp->mnt_flag |= MNT_MPWANT;
+               sleep((caddr_t)&mp->mnt_flag, PVFS);
+       }
+       if (mp->mnt_flag & MNT_UNMOUNT)
+               return (1);
+       mp->mnt_flag |= MNT_MPBUSY;
+       return (0);
+}
+
+/*
+ * Free a busy filesystem.
+ * Panic if filesystem is not busy.
+ */
+vfs_unbusy(mp)
+       register struct mount *mp;
+{
+
+       if ((mp->mnt_flag & MNT_MPBUSY) == 0)
+               panic("vfs_unbusy: not busy");
+       mp->mnt_flag &= ~MNT_MPBUSY;
+       if (mp->mnt_flag & MNT_MPWANT) {
+               mp->mnt_flag &= ~MNT_MPWANT;
+               wakeup((caddr_t)&mp->mnt_flag);
+       }
+}
+
+/*
+ * Lookup a mount point by filesystem identifier.
+ */
+struct mount *
+getvfs(fsid)
+       fsid_t *fsid;
+{
+       register struct mount *mp;
+
+       mp = rootfs;
+       do {
+               if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
+                   mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
+                       return (mp);
+               }
+               mp = mp->mnt_next;
+       } while (mp != rootfs);
+       return ((struct mount *)0);
+}
+
+/*
+ * Set vnode attributes to VNOVAL
+ */
+void vattr_null(vap)
+       register struct vattr *vap;
+{
+
+       vap->va_type = VNON;
+       vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
+               vap->va_fsid = vap->va_fileid = vap->va_size =
+               vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
+               vap->va_bytes = vap->va_bytes_rsv =
+               vap->va_atime.tv_sec = vap->va_atime.tv_usec =
+               vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
+               vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
+               vap->va_flags = vap->va_gen = VNOVAL;
+}
+
+/*
+ * Routines having to do with the management of the vnode table.
+ */
+struct vnode *vfreeh, **vfreet;
+extern struct vnodeops dead_vnodeops, spec_vnodeops;
+extern void vclean();
+long numvnodes;
+struct vattr va_null;
+
+/*
+ * Initialize the vnode structures and initialize each file system type.
+ */
+vfsinit()
+{
+       struct vfsops **vfsp;
+
+       /*
+        * Initialize the vnode name cache
+        */
+       nchinit();
+       /*
+        * Initialize each file system type.
+        */
+       vattr_null(&va_null);
+       for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
+               if (*vfsp == NULL)
+                       continue;
+               (*(*vfsp)->vfs_init)();
+       }
+}
+
+/*
+ * Return the next vnode from the free list.
+ */
+getnewvnode(tag, mp, vops, vpp)
+       enum vtagtype tag;
+       struct mount *mp;
+       struct vnodeops *vops;
+       struct vnode **vpp;
+{
+       register struct vnode *vp, *vq;
+
+       if (numvnodes < desiredvnodes) {
+               vp = (struct vnode *)malloc((u_long)sizeof *vp,
+                   M_VNODE, M_WAITOK);
+               bzero((char *)vp, sizeof *vp);
+               numvnodes++;
+       } else {
+               if ((vp = vfreeh) == NULL) {
+                       tablefull("vnode");
+                       *vpp = 0;
+                       return (ENFILE);
+               }
+               if (vp->v_usecount)
+                       panic("free vnode isn't");
+               if (vq = vp->v_freef)
+                       vq->v_freeb = &vfreeh;
+               else
+                       vfreet = &vfreeh;
+               vfreeh = vq;
+               vp->v_freef = NULL;
+               vp->v_freeb = NULL;
+               if (vp->v_type != VBAD)
+                       vgone(vp);
+               vp->v_flag = 0;
+               vp->v_lastr = 0;
+               vp->v_socket = 0;
+       }
+       vp->v_type = VNON;
+       cache_purge(vp);
+       vp->v_tag = tag;
+       vp->v_op = vops;
+       insmntque(vp, mp);
+       VREF(vp);
+       *vpp = vp;
+       return (0);
+}
+
+/*
+ * Move a vnode from one mount queue to another.
+ */
+insmntque(vp, mp)
+       register struct vnode *vp;
+       register struct mount *mp;
+{
+       register struct vnode *vq;
+
+       /*
+        * Delete from old mount point vnode list, if on one.
+        */
+       if (vp->v_mountb) {
+               if (vq = vp->v_mountf)
+                       vq->v_mountb = vp->v_mountb;
+               *vp->v_mountb = vq;
+       }
+       /*
+        * Insert into list of vnodes for the new mount point, if available.
+        */
+       vp->v_mount = mp;
+       if (mp == NULL) {
+               vp->v_mountf = NULL;
+               vp->v_mountb = NULL;
+               return;
+       }
+       if (vq = mp->mnt_mounth)
+               vq->v_mountb = &vp->v_mountf;
+       vp->v_mountf = vq;
+       vp->v_mountb = &mp->mnt_mounth;
+       mp->mnt_mounth = vp;
+}
+
+/*
+ * Make sure all write-behind blocks associated
+ * with mount point are flushed out (from sync).
+ */
+mntflushbuf(mountp, flags)
+       struct mount *mountp;
+       int flags;
+{
+       register struct vnode *vp;
+
+       if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
+               panic("mntflushbuf: not busy");
+loop:
+       for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
+               if (VOP_ISLOCKED(vp))
+                       continue;
+               if (vget(vp))
+                       goto loop;
+               vflushbuf(vp, flags);
+               vput(vp);
+               if (vp->v_mount != mountp)
+                       goto loop;
+       }
+}
+
+/*
+ * Flush all dirty buffers associated with a vnode.
+ */
+vflushbuf(vp, flags)
+       register struct vnode *vp;
+       int flags;
+{
+       register struct buf *bp;
+       struct buf *nbp;
+       int s;
+
+loop:
+       s = splbio();
+       for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
+               nbp = bp->b_blockf;
+               if ((bp->b_flags & B_BUSY))
+                       continue;
+               if ((bp->b_flags & B_DELWRI) == 0)
+                       panic("vflushbuf: not dirty");
+               bremfree(bp);
+               bp->b_flags |= B_BUSY;
+               splx(s);
+               /*
+                * Wait for I/O associated with indirect blocks to complete,
+                * since there is no way to quickly wait for them below.
+                * NB: This is really specific to ufs, but is done here
+                * as it is easier and quicker.
+                */
+               if (bp->b_vp == vp || (flags & B_SYNC) == 0)
+                       (void) bawrite(bp);
+               else
+                       (void) bwrite(bp);
+               goto loop;
+       }
+       splx(s);
+       if ((flags & B_SYNC) == 0)
+               return;
+       s = splbio();
+       while (vp->v_numoutput) {
+               vp->v_flag |= VBWAIT;
+               sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
+       }
+       splx(s);
+       if (vp->v_dirtyblkhd) {
+               vprint("vflushbuf: dirty", vp);
+               goto loop;
+       }
+}
+
+/*
+ * Update outstanding I/O count and do wakeup if requested.
+ */
+vwakeup(bp)
+       register struct buf *bp;
+{
+       register struct vnode *vp;
+
+       bp->b_dirtyoff = bp->b_dirtyend = 0;
+       if (vp = bp->b_vp) {
+               vp->v_numoutput--;
+               if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
+                       if (vp->v_numoutput < 0)
+                               panic("vwakeup: neg numoutput");
+                       vp->v_flag &= ~VBWAIT;
+                       wakeup((caddr_t)&vp->v_numoutput);
+               }
+       }
+}
+
+/*
+ * Invalidate in core blocks belonging to closed or umounted filesystem
+ *
+ * Go through the list of vnodes associated with the file system;
+ * for each vnode invalidate any buffers that it holds. Normally
+ * this routine is preceeded by a bflush call, so that on a quiescent
+ * filesystem there will be no dirty buffers when we are done. Binval
+ * returns the count of dirty buffers when it is finished.
+ */
+mntinvalbuf(mountp)
+       struct mount *mountp;
+{
+       register struct vnode *vp;
+       int dirty = 0;
+
+       if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
+               panic("mntinvalbuf: not busy");
+loop:
+       for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
+               if (vget(vp))
+                       goto loop;
+               dirty += vinvalbuf(vp, 1);
+               vput(vp);
+               if (vp->v_mount != mountp)
+                       goto loop;
+       }
+       return (dirty);
+}
+
+/*
+ * Flush out and invalidate all buffers associated with a vnode.
+ * Called with the underlying object locked.
+ */
+vinvalbuf(vp, save)
+       register struct vnode *vp;
+       int save;
+{
+       register struct buf *bp;
+       struct buf *nbp, *blist;
+       int s, dirty = 0;
+
+       for (;;) {
+               if (blist = vp->v_dirtyblkhd)
+                       /* void */;
+               else if (blist = vp->v_cleanblkhd)
+                       /* void */;
+               else
+                       break;
+               for (bp = blist; bp; bp = nbp) {
+                       nbp = bp->b_blockf;
+                       s = splbio();
+                       if (bp->b_flags & B_BUSY) {
+                               bp->b_flags |= B_WANTED;
+                               sleep((caddr_t)bp, PRIBIO + 1);
+                               splx(s);
+                               break;
+                       }
+                       bremfree(bp);
+                       bp->b_flags |= B_BUSY;
+                       splx(s);
+                       if (save && (bp->b_flags & B_DELWRI)) {
+                               dirty++;
+                               (void) bwrite(bp);
+                               break;
+                       }
+                       if (bp->b_vp != vp)
+                               reassignbuf(bp, bp->b_vp);
+                       else
+                               bp->b_flags |= B_INVAL;
+                       brelse(bp);
+               }
+       }
+       if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
+               panic("vinvalbuf: flush failed");
+       return (dirty);
+}
+
+/*
+ * Associate a buffer with a vnode.
+ */
+bgetvp(vp, bp)
+       register struct vnode *vp;
+       register struct buf *bp;
+{
+       register struct vnode *vq;
+       register struct buf *bq;
+
+       if (bp->b_vp)
+               panic("bgetvp: not free");
+       VHOLD(vp);
+       bp->b_vp = vp;
+       if (vp->v_type == VBLK || vp->v_type == VCHR)
+               bp->b_dev = vp->v_rdev;
+       else
+               bp->b_dev = NODEV;
+       /*
+        * Insert onto list for new vnode.
+        */
+       if (bq = vp->v_cleanblkhd)
+               bq->b_blockb = &bp->b_blockf;
+       bp->b_blockf = bq;
+       bp->b_blockb = &vp->v_cleanblkhd;
+       vp->v_cleanblkhd = bp;
+}
+
+/*
+ * Disassociate a buffer from a vnode.
+ */
+brelvp(bp)
+       register struct buf *bp;
+{
+       struct buf *bq;
+       struct vnode *vp;
+
+       if (bp->b_vp == (struct vnode *) 0)
+               panic("brelvp: NULL");
+       /*
+        * Delete from old vnode list, if on one.
+        */
+       if (bp->b_blockb) {
+               if (bq = bp->b_blockf)
+                       bq->b_blockb = bp->b_blockb;
+               *bp->b_blockb = bq;
+               bp->b_blockf = NULL;
+               bp->b_blockb = NULL;
+       }
+       vp = bp->b_vp;
+       bp->b_vp = (struct vnode *) 0;
+       HOLDRELE(vp);
+}
+
+/*
+ * Reassign a buffer from one vnode to another.
+ * Used to assign file specific control information
+ * (indirect blocks) to the vnode to which they belong.
+ */
+reassignbuf(bp, newvp)
+       register struct buf *bp;
+       register struct vnode *newvp;
+{
+       register struct buf *bq, **listheadp;
+
+       if (newvp == NULL)
+               panic("reassignbuf: NULL");
+       /*
+        * Delete from old vnode list, if on one.
+        */
+       if (bp->b_blockb) {
+               if (bq = bp->b_blockf)
+                       bq->b_blockb = bp->b_blockb;
+               *bp->b_blockb = bq;
+       }
+       /*
+        * If dirty, put on list of dirty buffers;
+        * otherwise insert onto list of clean buffers.
+        */
+       if (bp->b_flags & B_DELWRI)
+               listheadp = &newvp->v_dirtyblkhd;
+       else
+               listheadp = &newvp->v_cleanblkhd;
+       if (bq = *listheadp)
+               bq->b_blockb = &bp->b_blockf;
+       bp->b_blockf = bq;
+       bp->b_blockb = listheadp;
+       *listheadp = bp;
+}
+
+/*
+ * Create a vnode for a block device.
+ * Used for root filesystem, argdev, and swap areas.
+ * Also used for memory file system special devices.
+ */
+bdevvp(dev, vpp)
+       dev_t dev;
+       struct vnode **vpp;
+{
+       register struct vnode *vp;
+       struct vnode *nvp;
+       int error;
+
+       if (dev == NODEV)
+               return (0);
+       error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
+       if (error) {
+               *vpp = 0;
+               return (error);
+       }
+       vp = nvp;
+       vp->v_type = VBLK;
+       if (nvp = checkalias(vp, dev, (struct mount *)0)) {
+               vput(vp);
+               vp = nvp;
+       }
+       *vpp = vp;
+       return (0);
+}
+
+/*
+ * Check to see if the new vnode represents a special device
+ * for which we already have a vnode (either because of
+ * bdevvp() or because of a different vnode representing
+ * the same block device). If such an alias exists, deallocate
+ * the existing contents and return the aliased vnode. The
+ * caller is responsible for filling it with its new contents.
+ */
+struct vnode *
+checkalias(nvp, nvp_rdev, mp)
+       register struct vnode *nvp;
+       dev_t nvp_rdev;
+       struct mount *mp;
+{
+       register struct vnode *vp;
+       struct vnode **vpp;
+
+       if (nvp->v_type != VBLK && nvp->v_type != VCHR)
+               return (NULLVP);
+
+       vpp = &speclisth[SPECHASH(nvp_rdev)];
+loop:
+       for (vp = *vpp; vp; vp = vp->v_specnext) {
+               if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
+                       continue;
+               /*
+                * Alias, but not in use, so flush it out.
+                */
+               if (vp->v_usecount == 0) {
+                       vgone(vp);
+                       goto loop;
+               }
+               if (vget(vp))
+                       goto loop;
+               break;
+       }
+       if (vp == NULL || vp->v_tag != VT_NON) {
+               MALLOC(nvp->v_specinfo, struct specinfo *,
+                       sizeof(struct specinfo), M_VNODE, M_WAITOK);
+               nvp->v_rdev = nvp_rdev;
+               nvp->v_hashchain = vpp;
+               nvp->v_specnext = *vpp;
+               nvp->v_specflags = 0;
+               *vpp = nvp;
+               if (vp != NULL) {
+                       nvp->v_flag |= VALIASED;
+                       vp->v_flag |= VALIASED;
+                       vput(vp);
+               }
+               return (NULLVP);
+       }
+       VOP_UNLOCK(vp);
+       vclean(vp, 0);
+       vp->v_op = nvp->v_op;
+       vp->v_tag = nvp->v_tag;
+       nvp->v_type = VNON;
+       insmntque(vp, mp);
+       return (vp);
+}
+
+/*
+ * Grab a particular vnode from the free list, increment its
+ * reference count and lock it. The vnode lock bit is set the
+ * vnode is being eliminated in vgone. The process is awakened
+ * when the transition is completed, and an error returned to
+ * indicate that the vnode is no longer usable (possibly having
+ * been changed to a new file system type).
+ */
+vget(vp)
+       register struct vnode *vp;
+{
+       register struct vnode *vq;
+
+       if (vp->v_flag & VXLOCK) {
+               vp->v_flag |= VXWANT;
+               sleep((caddr_t)vp, PINOD);
+               return (1);
+       }
+       if (vp->v_usecount == 0) {
+               if (vq = vp->v_freef)
+                       vq->v_freeb = vp->v_freeb;
+               else
+                       vfreet = vp->v_freeb;
+               *vp->v_freeb = vq;
+               vp->v_freef = NULL;
+               vp->v_freeb = NULL;
+       }
+       VREF(vp);
+       VOP_LOCK(vp);
+       return (0);
+}
+
+/*
+ * Vnode reference, just increment the count
+ */
+void vref(vp)
+       struct vnode *vp;
+{
+
+       vp->v_usecount++;
+}
+
+/*
+ * vput(), just unlock and vrele()
+ */
+void vput(vp)
+       register struct vnode *vp;
+{
+       VOP_UNLOCK(vp);
+       vrele(vp);
+}
+
+/*
+ * Vnode release.
+ * If count drops to zero, call inactive routine and return to freelist.
+ */
+void vrele(vp)
+       register struct vnode *vp;
+{
+       struct proc *p = curproc;               /* XXX */
+
+#ifdef DIAGNOSTIC
+       if (vp == NULL)
+               panic("vrele: null vp");
+#endif
+       vp->v_usecount--;
+       if (vp->v_usecount > 0)
+               return;
+#ifdef DIAGNOSTIC
+       if (vp->v_usecount != 0 || vp->v_writecount != 0) {
+               vprint("vrele: bad ref count", vp);
+               panic("vrele: ref cnt");
+       }
+#endif
+       if (vfreeh == NULLVP) {
+               /*
+                * insert into empty list
+                */
+               vfreeh = vp;
+               vp->v_freeb = &vfreeh;
+       } else {
+               /*
+                * insert at tail of list
+                */
+               *vfreet = vp;
+               vp->v_freeb = vfreet;
+       }
+       vp->v_freef = NULL;
+       vfreet = &vp->v_freef;
+       VOP_INACTIVE(vp, p);
+}
+
+/*
+ * Page or buffer structure gets a reference.
+ */
+vhold(vp)
+       register struct vnode *vp;
+{
+
+       vp->v_holdcnt++;
+}
+
+/*
+ * Page or buffer structure frees a reference.
+ */
+holdrele(vp)
+       register struct vnode *vp;
+{
+
+       if (vp->v_holdcnt <= 0)
+               panic("holdrele: holdcnt");
+       vp->v_holdcnt--;
+}
+
+/*
+ * Remove any vnodes in the vnode table belonging to mount point mp.
+ *
+ * If MNT_NOFORCE is specified, there should not be any active ones,
+ * return error if any are found (nb: this is a user error, not a
+ * system error). If MNT_FORCE is specified, detach any active vnodes
+ * that are found.
+ */
+int busyprt = 0;       /* patch to print out busy vnodes */
+
+vflush(mp, skipvp, flags)
+       struct mount *mp;
+       struct vnode *skipvp;
+       int flags;
+{
+       register struct vnode *vp, *nvp;
+       int busy = 0;
+
+       if ((mp->mnt_flag & MNT_MPBUSY) == 0)
+               panic("vflush: not busy");
+loop:
+       for (vp = mp->mnt_mounth; vp; vp = nvp) {
+               if (vp->v_mount != mp)
+                       goto loop;
+               nvp = vp->v_mountf;
+               /*
+                * Skip over a selected vnode.
+                */
+               if (vp == skipvp)
+                       continue;
+               /*
+                * Skip over a vnodes marked VSYSTEM.
+                */
+               if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
+                       continue;
+               /*
+                * With v_usecount == 0, all we need to do is clear
+                * out the vnode data structures and we are done.
+                */
+               if (vp->v_usecount == 0) {
+                       vgone(vp);
+                       continue;
+               }
+               /*
+                * For block or character devices, revert to an
+                * anonymous device. For all other files, just kill them.
+                */
+               if (flags & FORCECLOSE) {
+                       if (vp->v_type != VBLK && vp->v_type != VCHR) {
+                               vgone(vp);
+                       } else {
+                               vclean(vp, 0);
+                               vp->v_op = &spec_vnodeops;
+                               insmntque(vp, (struct mount *)0);
+                       }
+                       continue;
+               }
+               if (busyprt)
+                       vprint("vflush: busy vnode", vp);
+               busy++;
+       }
+       if (busy)
+               return (EBUSY);
+       return (0);
+}
+
+/*
+ * Disassociate the underlying file system from a vnode.
+ */
+void vclean(vp, flags)
+       register struct vnode *vp;
+       int flags;
+{
+       struct vnodeops *origops;
+       int active;
+       struct proc *p = curproc;       /* XXX */
+
+       /*
+        * Check to see if the vnode is in use.
+        * If so we have to reference it before we clean it out
+        * so that its count cannot fall to zero and generate a
+        * race against ourselves to recycle it.
+        */
+       if (active = vp->v_usecount)
+               VREF(vp);
+       /*
+        * Prevent the vnode from being recycled or
+        * brought into use while we clean it out.
+        */
+       if (vp->v_flag & VXLOCK)
+               panic("vclean: deadlock");
+       vp->v_flag |= VXLOCK;
+       /*
+        * Even if the count is zero, the VOP_INACTIVE routine may still
+        * have the object locked while it cleans it out. The VOP_LOCK
+        * ensures that the VOP_INACTIVE routine is done with its work.
+        * For active vnodes, it ensures that no other activity can
+        * occur while the buffer list is being cleaned out.
+        */
+       VOP_LOCK(vp);
+       if (flags & DOCLOSE)
+               vinvalbuf(vp, 1);
+       /*
+        * Prevent any further operations on the vnode from
+        * being passed through to the old file system.
+        */
+       origops = vp->v_op;
+       vp->v_op = &dead_vnodeops;
+       vp->v_tag = VT_NON;
+       /*
+        * If purging an active vnode, it must be unlocked, closed,
+        * and deactivated before being reclaimed.
+        */
+       (*(origops->vop_unlock))(vp);
+       if (active) {
+               if (flags & DOCLOSE)
+                       (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p);
+               (*(origops->vop_inactive))(vp, p);
+       }
+       /*
+        * Reclaim the vnode.
+        */
+       if ((*(origops->vop_reclaim))(vp))
+               panic("vclean: cannot reclaim");
+       if (active)
+               vrele(vp);
+       /*
+        * Done with purge, notify sleepers in vget of the grim news.
+        */
+       vp->v_flag &= ~VXLOCK;
+       if (vp->v_flag & VXWANT) {
+               vp->v_flag &= ~VXWANT;
+               wakeup((caddr_t)vp);
+       }
+}
+
+/*
+ * Eliminate all activity associated with  the requested vnode
+ * and with all vnodes aliased to the requested vnode.
+ */
+void vgoneall(vp)
+       register struct vnode *vp;
+{
+       register struct vnode *vq;
+
+       if (vp->v_flag & VALIASED) {
+               /*
+                * If a vgone (or vclean) is already in progress,
+                * wait until it is done and return.
+                */
+               if (vp->v_flag & VXLOCK) {
+                       vp->v_flag |= VXWANT;
+                       sleep((caddr_t)vp, PINOD);
+                       return;
+               }
+               /*
+                * Ensure that vp will not be vgone'd while we
+                * are eliminating its aliases.
+                */
+               vp->v_flag |= VXLOCK;
+               while (vp->v_flag & VALIASED) {
+                       for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
+                               if (vq->v_rdev != vp->v_rdev ||
+                                   vq->v_type != vp->v_type || vp == vq)
+                                       continue;
+                               vgone(vq);
+                               break;
+                       }
+               }
+               /*
+                * Remove the lock so that vgone below will
+                * really eliminate the vnode after which time
+                * vgone will awaken any sleepers.
+                */
+               vp->v_flag &= ~VXLOCK;
+       }
+       vgone(vp);
+}
+
+/*
+ * Eliminate all activity associated with a vnode
+ * in preparation for reuse.
+ */
+void vgone(vp)
+       register struct vnode *vp;
+{
+       register struct vnode *vq;
+       struct vnode *vx;
+       long count;
+
+       /*
+        * If a vgone (or vclean) is already in progress,
+        * wait until it is done and return.
+        */
+       if (vp->v_flag & VXLOCK) {
+               vp->v_flag |= VXWANT;
+               sleep((caddr_t)vp, PINOD);
+               return;
+       }
+       /*
+        * Clean out the filesystem specific data.
+        */
+       vclean(vp, DOCLOSE);
+       /*
+        * Delete from old mount point vnode list, if on one.
+        */
+       if (vp->v_mountb) {
+               if (vq = vp->v_mountf)
+                       vq->v_mountb = vp->v_mountb;
+               *vp->v_mountb = vq;
+               vp->v_mountf = NULL;
+               vp->v_mountb = NULL;
+       }
+       /*
+        * If special device, remove it from special device alias list.
+        */
+       if (vp->v_type == VBLK || vp->v_type == VCHR) {
+               if (*vp->v_hashchain == vp) {
+                       *vp->v_hashchain = vp->v_specnext;
+               } else {
+                       for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
+                               if (vq->v_specnext != vp)
+                                       continue;
+                               vq->v_specnext = vp->v_specnext;
+                               break;
+                       }
+                       if (vq == NULL)
+                               panic("missing bdev");
+               }
+               if (vp->v_flag & VALIASED) {
+                       count = 0;
+                       for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
+                               if (vq->v_rdev != vp->v_rdev ||
+                                   vq->v_type != vp->v_type)
+                                       continue;
+                               count++;
+                               vx = vq;
+                       }
+                       if (count == 0)
+                               panic("missing alias");
+                       if (count == 1)
+                               vx->v_flag &= ~VALIASED;
+                       vp->v_flag &= ~VALIASED;
+               }
+               FREE(vp->v_specinfo, M_VNODE);
+               vp->v_specinfo = NULL;
+       }
+       /*
+        * If it is on the freelist, move it to the head of the list.
+        */
+       if (vp->v_freeb) {
+               if (vq = vp->v_freef)
+                       vq->v_freeb = vp->v_freeb;
+               else
+                       vfreet = vp->v_freeb;
+               *vp->v_freeb = vq;
+               vp->v_freef = vfreeh;
+               vp->v_freeb = &vfreeh;
+               vfreeh->v_freeb = &vp->v_freef;
+               vfreeh = vp;
+       }
+       vp->v_type = VBAD;
+}
+
+/*
+ * Lookup a vnode by device number.
+ */
+vfinddev(dev, type, vpp)
+       dev_t dev;
+       enum vtype type;
+       struct vnode **vpp;
+{
+       register struct vnode *vp;
+
+       for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
+               if (dev != vp->v_rdev || type != vp->v_type)
+                       continue;
+               *vpp = vp;
+               return (0);
+       }
+       return (1);
+}
+
+/*
+ * Calculate the total number of references to a special device.
+ */
+vcount(vp)
+       register struct vnode *vp;
+{
+       register struct vnode *vq;
+       int count;
+
+       if ((vp->v_flag & VALIASED) == 0)
+               return (vp->v_usecount);
+loop:
+       for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
+               if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
+                       continue;
+               /*
+                * Alias, but not in use, so flush it out.
+                */
+               if (vq->v_usecount == 0) {
+                       vgone(vq);
+                       goto loop;
+               }
+               count += vq->v_usecount;
+       }
+       return (count);
+}
+
+/*
+ * Print out a description of a vnode.
+ */
+static char *typename[] =
+   { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
+
+vprint(label, vp)
+       char *label;
+       register struct vnode *vp;
+{
+       char buf[64];
+
+       if (label != NULL)
+               printf("%s: ", label);
+       printf("type %s, usecount %d, writecount %d, refcount %d,",
+               typename[vp->v_type], vp->v_usecount, vp->v_writecount,
+               vp->v_holdcnt);
+       buf[0] = '\0';
+       if (vp->v_flag & VROOT)
+               strcat(buf, "|VROOT");
+       if (vp->v_flag & VTEXT)
+               strcat(buf, "|VTEXT");
+       if (vp->v_flag & VSYSTEM)
+               strcat(buf, "|VSYSTEM");
+       if (vp->v_flag & VXLOCK)
+               strcat(buf, "|VXLOCK");
+       if (vp->v_flag & VXWANT)
+               strcat(buf, "|VXWANT");
+       if (vp->v_flag & VBWAIT)
+               strcat(buf, "|VBWAIT");
+       if (vp->v_flag & VALIASED)
+               strcat(buf, "|VALIASED");
+       if (buf[0] != '\0')
+               printf(" flags (%s)", &buf[1]);
+       printf("\n\t");
+       VOP_PRINT(vp);
+}
+
+#ifdef DEBUG
+/*
+ * List all of the locked vnodes in the system.
+ * Called when debugging the kernel.
+ */
+printlockedvnodes()
+{
+       register struct mount *mp;
+       register struct vnode *vp;
+
+       printf("Locked vnodes\n");
+       mp = rootfs;
+       do {
+               for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf)
+                       if (VOP_ISLOCKED(vp))
+                               vprint((char *)0, vp);
+               mp = mp->mnt_next;
+       } while (mp != rootfs);
+}
+#endif
+
+int kinfo_vdebug = 1;
+int kinfo_vgetfailed;
+#define KINFO_VNODESLOP        10
+/*
+ * Dump vnode list (via kinfo).
+ * Copyout address of vnode followed by vnode.
+ */
+/* ARGSUSED */
+kinfo_vnode(op, where, acopysize, arg, aneeded)
+       int op;
+       char *where;
+       int *acopysize, arg, *aneeded;
+{
+       register struct mount *mp = rootfs;
+       struct mount *omp;
+       struct vnode *vp;
+       register char *bp = where, *savebp;
+       char *ewhere = where + *acopysize;
+       int error;
+
+#define VPTRSZ sizeof (struct vnode *)
+#define VNODESZ        sizeof (struct vnode)
+       if (where == NULL) {
+               *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
+               return (0);
+       }
+               
+       do {
+               if (vfs_busy(mp)) {
+                       mp = mp->mnt_next;
+                       continue;
+               }
+               savebp = bp;
+again:
+               for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
+                       /*
+                        * Check that the vp is still associated with
+                        * this filesystem.  RACE: could have been
+                        * recycled onto the same filesystem.
+                        */
+                       if (vp->v_mount != mp) {
+                               if (kinfo_vdebug)
+                                       printf("kinfo: vp changed\n");
+                               bp = savebp;
+                               goto again;
+                       }
+                       if ((bp + VPTRSZ + VNODESZ <= ewhere) && 
+                           ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
+                            (error = copyout((caddr_t)vp, bp + VPTRSZ, 
+                             VNODESZ))))
+                               return (error);
+                       bp += VPTRSZ + VNODESZ;
+               }
+               omp = mp;
+               mp = mp->mnt_next;
+               vfs_unbusy(omp);
+       } while (mp != rootfs);
+
+       *aneeded = bp - where;
+       if (bp > ewhere)
+               *acopysize = ewhere - where;
+       else
+               *acopysize = bp - where;
+       return (0);
+}
diff --git a/usr/src/sys.386bsd/net/af.c b/usr/src/sys.386bsd/net/af.c
new file mode 100644 (file)
index 0000000..4684e09
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1983, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)af.c        7.6 (Berkeley) 6/28/90
+ */
+
+#include "param.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "af.h"
+
+/*
+ * Nothing in the file should be needed anymore.
+ */
+int SocketSizeForInspection = sizeof (struct socket);
diff --git a/usr/src/sys.386bsd/net/af.h b/usr/src/sys.386bsd/net/af.h
new file mode 100644 (file)
index 0000000..3a47cdc
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1980, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)af.h        7.5 (Berkeley) 6/28/90
+ */
+
+/*
+ * This file is obsolete, I think.  kls 12/21/88
+
+ * Address family routines,
+ * used in handling generic sockaddr structures.
+ *
+ * Hash routine is called
+ *     af_hash(addr, h);
+ *     struct sockaddr *addr; struct afhash *h;
+ * producing an afhash structure for addr.
+ *
+ * Netmatch routine is called
+ *     af_netmatch(addr1, addr2);
+ * where addr1 and addr2 are sockaddr *.  Returns 1 if network
+ * values match, 0 otherwise.
+struct afswitch {
+       int     (*af_hash)();
+       int     (*af_netmatch)();
+};
+
+struct afhash {
+       u_int   afh_hosthash;
+       u_int   afh_nethash;
+};
+
+#ifdef KERNEL
+struct afswitch afswitch[];
+#endif
+ */
diff --git a/usr/src/sys.386bsd/net/bpf.h b/usr/src/sys.386bsd/net/bpf.h
new file mode 100644 (file)
index 0000000..5d7ad06
--- /dev/null
@@ -0,0 +1,219 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)bpf.h       7.1 (Berkeley) 5/7/91
+ *
+ * @(#) $Header: bpf.h,v 1.20 91/04/24 22:06:24 mccanne Locked $ (LBL)
+ */
+
+/*
+ * Alignment macros.  BPF_WORDALIGN rounds up to the next 
+ * even multiple of BPF_ALIGNMENT. 
+ */
+#define BPF_ALIGNMENT sizeof(long)
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_MAXINSNS 512
+#define BPF_MAXBUFSIZE 0x8000
+
+/*
+ *  Structure for BIOCSETF.
+ */
+struct bpf_program {
+       u_int bf_len;
+       struct bpf_insn *bf_insns;
+};
+/*
+ * Struct returned by BIOCGSTATS.
+ */
+struct bpf_stat {
+       u_int bs_recv;          /* number of packets received */
+       u_int bs_drop;          /* number of packets dropped */
+};
+
+/*
+ * BPF ioctls
+ *
+ * The first set is for compatibility with Sun's pcc style
+ * header files.  If your using gcc, we assume that you
+ * have run fixincludes so the latter set should work.
+ */
+#if defined(sun) && !defined(__GNUC__)
+#define        BIOCGFLEN       _IOR(B,101, u_int)
+#define        BIOCGBLEN       _IOR(B,102, u_int)
+#define        BIOCSETF        _IOW(B,103, struct bpf_program)
+#define        BIOCFLUSH       _IO(B,104)
+#define BIOCPROMISC    _IO(B,105)
+#define        BIOCGDLT        _IOR(B,106, u_int)
+#define BIOCGETIF      _IOR(B,107, struct ifreq)
+#define BIOCSETIF      _IOW(B,108, struct ifreq)
+#define BIOCSRTIMEOUT  _IOW(B,109, struct timeval)
+#define BIOCGRTIMEOUT  _IOR(B,110, struct timeval)
+#define BIOCGSTATS     _IOR(B,111, struct bpf_stat)
+#define BIOCIMMEDIATE  _IOW(B,112, u_int)
+#else
+#define        BIOCGFLEN       _IOR('B',101, u_int)
+#define        BIOCGBLEN       _IOR('B',102, u_int)
+#define        BIOCSETF        _IOW('B',103, struct bpf_program)
+#define        BIOCFLUSH       _IO('B',104)
+#define BIOCPROMISC    _IO('B',105)
+#define        BIOCGDLT        _IOR('B',106, u_int)
+#define BIOCGETIF      _IOR('B',107, struct ifreq)
+#define BIOCSETIF      _IOW('B',108, struct ifreq)
+#define BIOCSRTIMEOUT  _IOW('B',109, struct timeval)
+#define BIOCGRTIMEOUT  _IOR('B',110, struct timeval)
+#define BIOCGSTATS     _IOR('B',111, struct bpf_stat)
+#define BIOCIMMEDIATE  _IOW('B',112, u_int)
+#endif
+
+/*
+ * Structure prepended to each packet.
+ */
+struct bpf_hdr {
+       struct timeval  bh_tstamp;      /* time stamp */
+       u_long          bh_caplen;      /* length of captured portion */
+       u_long          bh_datalen;     /* original length of packet */
+       u_short         bh_hdrlen;      /* length of bpf header (this struct
+                                          plus alignment padding) */
+};
+/*
+ * Because the structure above is not a multiple of 4 bytes, some compilers
+ * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work.
+ * Only the kernel needs to know about it; applications use bh_hdrlen.
+ */
+#ifdef KERNEL
+#define SIZEOF_BPF_HDR 18
+#endif
+
+/*
+ * Data-link level type codes.
+ * Currently, only DLT_EN10MB and DLT_SLIP are supported.
+ */
+#define DLT_EN10MB     1       /* Ethernet (10Mb) */
+#define DLT_EN3MB      2       /* Experimental Ethernet (3Mb) */
+#define DLT_AX25       3       /* Amateur Radio AX.25 */
+#define DLT_PRONET     4       /* Proteon ProNET Token Ring */
+#define DLT_CHAOS      5       /* Chaos */
+#define DLT_IEEE802    6       /* IEEE 802 Networks */
+#define DLT_ARCNET     7       /* ARCNET */
+#define DLT_SLIP       8       /* Serial Line IP */
+#define DLT_PPP                9       /* Point-to-point Protocol */
+#define DLT_FDDI       10      /* FDDI */
+
+/*
+ * The instruction encondings.
+ */
+/* classes <2:0> */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define                BPF_LD          0x00
+#define                BPF_LDX         0x01
+#define                BPF_ST          0x02
+#define                BPF_STX         0x03
+#define                BPF_ALU         0x04
+#define                BPF_JMP         0x05
+#define                BPF_RET         0x06
+#define                BPF_MISC        0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define                BPF_W           0x00
+#define                BPF_H           0x08
+#define                BPF_B           0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define                BPF_IMM         0x00
+#define                BPF_ABS         0x20
+#define                BPF_IND         0x40
+#define                BPF_MEM         0x60
+#define                BPF_LEN         0x80
+#define                BPF_MSH         0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code)   ((code) & 0xf0)
+#define                BPF_ADD         0x00
+#define                BPF_SUB         0x10
+#define                BPF_MUL         0x20
+#define                BPF_DIV         0x30
+#define                BPF_OR          0x40
+#define                BPF_AND         0x50
+#define                BPF_LSH         0x60
+#define                BPF_RSH         0x70
+#define                BPF_NEG         0x80
+#define                BPF_JA          0x00
+#define                BPF_JEQ         0x10
+#define                BPF_JGT         0x20
+#define                BPF_JGE         0x30
+#define                BPF_JSET        0x40
+#define BPF_SRC(code)  ((code) & 0x08)
+#define                BPF_K           0x00
+#define                BPF_X           0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define                BPF_A           0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define                BPF_TAX         0x00
+#define                BPF_TXA         0x80
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+       u_short code;
+       u_char  jt;
+       u_char  jf;
+       long    k;
+};
+
+/*
+ * Macros for insn array initializers.
+ */
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+#ifdef KERNEL
+extern u_int bpf_filter();
+extern void bpfattach();
+extern void bpf_tap();
+extern void bpf_mtap();
+#endif
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
diff --git a/usr/src/sys.386bsd/net/bpf_filter.c b/usr/src/sys.386bsd/net/bpf_filter.c
new file mode 100644 (file)
index 0000000..52a92c7
--- /dev/null
@@ -0,0 +1,549 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)bpf_filter.c        7.2 (Berkeley) 5/14/91
+ *
+ * static char rcsid[] =
+ * "@(#) $Header: bpf_filter.c,v 1.10 91/04/24 22:07:07 mccanne Locked $ (LBL)";
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#ifdef sun
+#include <netinet/in.h>
+#endif
+
+#if defined(sparc) || defined(mips)
+#define ALIGN
+#endif
+
+#ifndef ALIGN
+#define EXTRACT_SHORT(p)       (ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p)                (ntohl(*(u_long *)p))
+#else
+#define EXTRACT_SHORT(p)\
+       ((u_short)\
+               (*((u_char *)(p)+0)<<8|\
+                *((u_char *)(p)+1)<<0))
+#define EXTRACT_LONG(p)\
+               (*((u_char *)(p)+0)<<24|\
+                *((u_char *)(p)+1)<<16|\
+                *((u_char *)(p)+2)<<8|\
+                *((u_char *)(p)+3)<<0)
+#endif
+
+#ifdef KERNEL
+#include <sys/mbuf.h>
+#define MINDEX(m, k) \
+{ \
+       register int len = m->m_len; \
+ \
+       while (k >= len) { \
+               k -= len; \
+               m = m->m_next; \
+               if (m == 0) \
+                       return 0; \
+               len = m->m_len; \
+       } \
+}
+
+static int
+m_xword(m, k, err)
+       register struct mbuf *m;
+       register int k, *err;
+{
+       register int len;
+       register u_char *cp, *np;
+       register struct mbuf *m0;
+
+       len = m->m_len;
+       while (k >= len) {
+               k -= len;
+               m = m->m_next;
+               if (m == 0)
+                       goto bad;
+               len = m->m_len;
+       }
+       cp = mtod(m, u_char *) + k;
+       if (len - k >= 4) {
+               *err = 0;
+               return EXTRACT_LONG(cp);
+       }
+       m0 = m->m_next;
+       if (m0 == 0 || m0->m_len + len - k < 4)
+               goto bad;
+       *err = 0;
+       np = mtod(m0, u_char *);
+       switch (len - k) {
+
+       case 1:
+               return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
+
+       case 2:
+               return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) | 
+                       np[1];
+
+       default:
+               return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) |
+                       np[0];
+       }
+    bad:
+       *err = 1;
+       return 0;
+}
+
+static int
+m_xhalf(m, k, err)
+       register struct mbuf *m;
+       register int k, *err;
+{
+       register int len;
+       register u_char *cp, *np;
+       register struct mbuf *m0;
+
+       len = m->m_len;
+       while (k >= len) {
+               k -= len;
+               m = m->m_next;
+               if (m == 0)
+                       goto bad;
+               len = m->m_len;
+       }
+       cp = mtod(m, u_char *) + k;
+       if (len - k >= 2) {
+               *err = 0;
+               return EXTRACT_SHORT(cp);
+       }
+       m0 = m->m_next;
+       if (m0 == 0)
+               goto bad;
+       *err = 0;
+       return (cp[k] << 8) | mtod(m0, u_char *)[0];
+ bad:
+       *err = 1;
+       return 0;
+}
+
+
+#endif
+
+/*
+ * Execute the filter program starting at pc on the packet p
+ * wirelen is the length of the original packet
+ * buflen is the amount of data present
+ */
+u_int
+bpf_filter(pc, p, wirelen, buflen)
+       register struct bpf_insn *pc;
+       register u_char *p;
+       u_int wirelen;
+       register u_int buflen;
+{
+       register long A, X;
+       register int k;
+       long mem[BPF_MEMWORDS];
+
+       if (pc == 0)
+               /*
+                * No filter means accept all.
+                */
+               return (u_int)-1;
+#ifdef lint
+       A = 0;
+       X = 0;
+#endif
+       --pc;
+       while (1) {
+               ++pc;
+               switch (pc->code) {
+
+               default:
+#ifdef KERNEL
+                       return 0;
+#else
+                       abort();
+#endif                 
+               case BPF_RET|BPF_K:
+                       return (u_int)pc->k;
+
+               case BPF_RET|BPF_A:
+                       return (u_int)A;
+
+               case BPF_LD|BPF_W|BPF_ABS:
+                       k = pc->k;
+                       if (k + sizeof(long) > buflen) {
+#ifdef KERNEL
+                               int merr;
+
+                               if (buflen != 0)
+                                       return 0;
+                               A = m_xword((struct mbuf *)p, k, &merr);
+                               if (merr != 0)
+                                       return 0;
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+#ifdef ALIGN
+                       if (((int)(p + k) & 3) != 0)
+                               A = EXTRACT_LONG(&p[k]);
+                       else
+#endif
+                               A = *(long *)(p + k);
+                       continue;
+
+               case BPF_LD|BPF_H|BPF_ABS:
+                       k = pc->k;
+                       if (k + sizeof(short) > buflen) {
+#ifdef KERNEL
+                               int merr;
+
+                               if (buflen != 0)
+                                       return 0;
+                               A = m_xhalf((struct mbuf *)p, k, &merr);
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+                       A = EXTRACT_SHORT(&p[k]);
+                       continue;
+
+               case BPF_LD|BPF_B|BPF_ABS:
+                       k = pc->k;
+                       if (k >= buflen) {
+#ifdef KERNEL
+                               register struct mbuf *m;
+
+                               if (buflen != 0)
+                                       return 0;
+                               m = (struct mbuf *)p;
+                               MINDEX(m, k);
+                               A = mtod(m, u_char *)[k];
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+                       A = p[k];
+                       continue;
+
+               case BPF_LD|BPF_W|BPF_LEN:
+                       A = wirelen;
+                       continue;
+
+               case BPF_LDX|BPF_W|BPF_LEN:
+                       X = wirelen;
+                       continue;
+
+               case BPF_LD|BPF_W|BPF_IND:
+                       k = X + pc->k;
+                       if (k + sizeof(long) > buflen) {
+#ifdef KERNEL
+                               int merr;
+
+                               if (buflen != 0)
+                                       return 0;
+                               A = m_xword((struct mbuf *)p, k, &merr);
+                               if (merr != 0)
+                                       return 0;
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+#ifdef ALIGN
+                       if (((int)(p + k) & 3) != 0)
+                               A = EXTRACT_LONG(&p[k]);
+                       else
+#endif
+                               A = *(long *)(p + k);
+                       continue;
+
+               case BPF_LD|BPF_H|BPF_IND:
+                       k = X + pc->k;
+                       if (k + sizeof(short) > buflen) {
+#ifdef KERNEL
+                               int merr;
+
+                               if (buflen != 0)
+                                       return 0;
+                               A = m_xhalf((struct mbuf *)p, k, &merr);
+                               if (merr != 0)
+                                       return 0;
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+                       A = EXTRACT_SHORT(&p[k]);
+                       continue;
+
+               case BPF_LD|BPF_B|BPF_IND:
+                       k = X + pc->k;
+                       if (k >= buflen) {
+#ifdef KERNEL
+                               register struct mbuf *m;
+
+                               if (buflen != 0)
+                                       return 0;
+                               m = (struct mbuf *)p;
+                               MINDEX(m, k);
+                               A = mtod(m, char *)[k];
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+                       A = p[k];
+                       continue;
+
+               case BPF_LDX|BPF_MSH|BPF_B:
+                       k = pc->k;
+                       if (k >= buflen) {
+#ifdef KERNEL
+                               register struct mbuf *m;
+
+                               if (buflen != 0)
+                                       return 0;
+                               m = (struct mbuf *)p;
+                               MINDEX(m, k);
+                               X = (mtod(m, char *)[k] & 0xf) << 2;
+                               continue;
+#else
+                               return 0;
+#endif
+                       }
+                       X = (p[pc->k] & 0xf) << 2;
+                       continue;
+
+               case BPF_LD|BPF_IMM:
+                       A = pc->k;
+                       continue;
+
+               case BPF_LDX|BPF_IMM:
+                       X = pc->k;
+                       continue;
+
+               case BPF_LD|BPF_MEM:
+                       A = mem[pc->k];
+                       continue;
+                       
+               case BPF_LDX|BPF_MEM:
+                       X = mem[pc->k];
+                       continue;
+
+               case BPF_ST:
+                       mem[pc->k] = A;
+                       continue;
+
+               case BPF_STX:
+                       mem[pc->k] = X;
+                       continue;
+
+               case BPF_JMP|BPF_JA:
+                       pc += pc->k;
+                       continue;
+
+               case BPF_JMP|BPF_JGT|BPF_K:
+                       pc += (A > pc->k) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_JMP|BPF_JGE|BPF_K:
+                       pc += (A >= pc->k) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_JMP|BPF_JEQ|BPF_K:
+                       pc += (A == pc->k) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_JMP|BPF_JSET|BPF_K:
+                       pc += (A & pc->k) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_JMP|BPF_JGT|BPF_X:
+                       pc += (A > X) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_JMP|BPF_JGE|BPF_X:
+                       pc += (A >= X) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_JMP|BPF_JEQ|BPF_X:
+                       pc += (A == X) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_JMP|BPF_JSET|BPF_X:
+                       pc += (A & X) ? pc->jt : pc->jf;
+                       continue;
+
+               case BPF_ALU|BPF_ADD|BPF_X:
+                       A += X;
+                       continue;
+                       
+               case BPF_ALU|BPF_SUB|BPF_X:
+                       A -= X;
+                       continue;
+                       
+               case BPF_ALU|BPF_MUL|BPF_X:
+                       A *= X;
+                       continue;
+                       
+               case BPF_ALU|BPF_DIV|BPF_X:
+                       if (X == 0)
+                               return 0;
+                       A /= X;
+                       continue;
+                       
+               case BPF_ALU|BPF_AND|BPF_X:
+                       A &= X;
+                       continue;
+                       
+               case BPF_ALU|BPF_OR|BPF_X:
+                       A |= X;
+                       continue;
+
+               case BPF_ALU|BPF_LSH|BPF_X:
+                       A <<= X;
+                       continue;
+
+               case BPF_ALU|BPF_RSH|BPF_X:
+                       A >>= X;
+                       continue;
+
+               case BPF_ALU|BPF_ADD|BPF_K:
+                       A += pc->k;
+                       continue;
+                       
+               case BPF_ALU|BPF_SUB|BPF_K:
+                       A -= pc->k;
+                       continue;
+                       
+               case BPF_ALU|BPF_MUL|BPF_K:
+                       A *= pc->k;
+                       continue;
+                       
+               case BPF_ALU|BPF_DIV|BPF_K:
+                       A /= pc->k;
+                       continue;
+                       
+               case BPF_ALU|BPF_AND|BPF_K:
+                       A &= pc->k;
+                       continue;
+                       
+               case BPF_ALU|BPF_OR|BPF_K:
+                       A |= pc->k;
+                       continue;
+
+               case BPF_ALU|BPF_LSH|BPF_K:
+                       A <<= pc->k;
+                       continue;
+
+               case BPF_ALU|BPF_RSH|BPF_K:
+                       A >>= pc->k;
+                       continue;
+
+               case BPF_ALU|BPF_NEG:
+                       A = -A;
+                       continue;
+
+               case BPF_MISC|BPF_TAX:
+                       X = A;
+                       continue;
+
+               case BPF_MISC|BPF_TXA:
+                       A = X;
+                       continue;
+               }
+       }
+}
+
+#ifdef KERNEL
+/*
+ * Return true if the 'fcode' is a valid filter program.
+ * The constraints are that each jump be forward and to a valid
+ * code.  The code must terminate with either an accept or reject. 
+ * 'valid' is an array for use by the routine (it must be at least
+ * 'len' bytes long).  
+ *
+ * The kernel needs to be able to verify an application's filter code.
+ * Otherwise, a bogus program could easily crash the system.
+ */
+int
+bpf_validate(f, len)
+       struct bpf_insn *f;
+       int len;
+{
+       register int i;
+       register struct bpf_insn *p;
+
+       for (i = 0; i < len; ++i) {
+               /*
+                * Check that that jumps are forward, and within 
+                * the code block.
+                */
+               p = &f[i];
+               if (BPF_CLASS(p->code) == BPF_JMP) {
+                       register int from = i + 1;
+
+                       if (BPF_OP(p->code) == BPF_JA) {
+                               if (from + p->k >= len)
+                                       return 0;
+                       }
+                       else if (from + p->jt >= len || from + p->jf >= len)
+                               return 0;
+               }
+               /*
+                * Check that memory operations use valid addresses.
+                */
+               if ((BPF_CLASS(p->code) == BPF_ST ||
+                    (BPF_CLASS(p->code) == BPF_LD && 
+                     (p->code & 0xe0) == BPF_MEM)) &&
+                   (p->k >= BPF_MEMWORDS || p->k < 0))
+                       return 0;
+               /*
+                * Check for constant division by 0.
+                */
+               if (p->code == BPF_ALU|BPF_DIV|BPF_K && p->k == 0)
+                       return;
+       }
+       return BPF_CLASS(f[len - 1].code) == BPF_RET;
+}
+#endif
diff --git a/usr/src/sys.386bsd/net/bpfdesc.h b/usr/src/sys.386bsd/net/bpfdesc.h
new file mode 100644 (file)
index 0000000..807f147
--- /dev/null
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)bpfdesc.h   7.1 (Berkeley) 5/7/91
+ *
+ * @(#) $Header: bpfdesc.h,v 1.7 90/12/04 01:05:01 mccanne Exp $ (LBL)
+ */
+
+/*
+ * Descriptor associated with each open bpf file.
+ */
+struct bpf_d {
+       struct bpf_d    *bd_next;       /* Linked list of descriptors */
+       /*
+        * Buffer slots: two mbuf clusters buffer the incoming packets.
+        *   The model has three slots.  Sbuf is always occupied.
+        *   sbuf (store) - Receive interrupt puts packets here.
+        *   hbuf (hold) - When sbuf is full, put cluster here and
+        *                 wakeup read (replace sbuf with fbuf).
+        *   fbuf (free) - When read is done, put cluster here.
+        * On receiving, if sbuf is full and fbuf is 0, packet is dropped.
+        */
+       caddr_t         bd_sbuf;        /* store slot */
+       caddr_t         bd_hbuf;        /* hold slot */
+       caddr_t         bd_fbuf;        /* free slot */
+       int             bd_slen;        /* current length of store buffer */
+       int             bd_hlen;        /* current length of hold buffer */
+
+       int             bd_bufsize;     /* absolute length of buffers */
+
+       struct bpf_if * bd_bif;         /* interface descriptor */
+       u_long          bd_rtout;       /* Read timeout in 'ticks' */
+       struct bpf_insn *bd_filter;     /* filter code */
+       u_long          bd_rcount;      /* number of packets received */
+       u_long          bd_dcount;      /* number of packets dropped */
+       struct proc *   bd_selproc;     /* process that last selected us */
+
+       u_char          bd_promisc;     /* true if listening promiscuously */
+       u_char          bd_state;       /* idle, waiting, or timed out */
+       u_char          bd_selcoll;     /* true if selects collide */
+       u_char          bd_immediate;   /* true to return on packet arrival */
+};
+
+/*
+ * Descriptor associated with each attached hardware interface.
+ */
+struct bpf_if {
+       struct bpf_if *bif_next;        /* list of all interfaces */
+       struct bpf_d *bif_dlist;        /* descriptor list */
+       struct bpf_if **bif_driverp;    /* pointer into softc */
+       u_int bif_dlt;                  /* link layer type */
+       u_int bif_hdrlen;               /* length of header (with padding) */
+       struct ifnet *bif_ifp;          /* correspoding interface */
+};
diff --git a/usr/src/sys.386bsd/net/if.c b/usr/src/sys.386bsd/net/if.c
new file mode 100644 (file)
index 0000000..dc395f5
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * Copyright (c) 1980, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if.c        7.14 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "mbuf.h"
+#include "systm.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "protosw.h"
+#include "proc.h"
+#include "kernel.h"
+#include "ioctl.h"
+
+#include "if.h"
+#include "af.h"
+#include "if_dl.h"
+#include "if_types.h"
+
+#include "ether.h"
+
+int    ifqmaxlen = IFQ_MAXLEN;
+
+/*
+ * Network interface utility routines.
+ *
+ * Routines with ifa_ifwith* names take sockaddr *'s as
+ * parameters.
+ */
+
+ifinit()
+{
+       register struct ifnet *ifp;
+
+       for (ifp = ifnet; ifp; ifp = ifp->if_next)
+               if (ifp->if_snd.ifq_maxlen == 0)
+                       ifp->if_snd.ifq_maxlen = ifqmaxlen;
+       if_slowtimo();
+}
+
+#ifdef vax
+/*
+ * Call each interface on a Unibus reset.
+ */
+ifubareset(uban)
+       int uban;
+{
+       register struct ifnet *ifp;
+
+       for (ifp = ifnet; ifp; ifp = ifp->if_next)
+               if (ifp->if_reset)
+                       (*ifp->if_reset)(ifp->if_unit, uban);
+}
+#endif
+
+int if_index = 0;
+struct ifaddr **ifnet_addrs;
+static char *sprint_d();
+
+/*
+ * Attach an interface to the
+ * list of "active" interfaces.
+ */
+if_attach(ifp)
+       struct ifnet *ifp;
+{
+       unsigned socksize, ifasize;
+       int namelen, unitlen;
+       char workbuf[12], *unitname;
+       register struct ifnet **p = &ifnet;
+       register struct sockaddr_dl *sdl;
+       register struct ifaddr *ifa;
+       static int if_indexlim = 8;
+       extern link_rtrequest(), ether_output();
+
+       while (*p)
+               p = &((*p)->if_next);
+       *p = ifp;
+       ifp->if_index = ++if_index;
+       if (ifnet_addrs == 0 || if_index >= if_indexlim) {
+               unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
+               struct ifaddr **q = (struct ifaddr **)
+                                       malloc(n, M_IFADDR, M_WAITOK);
+               if (ifnet_addrs) {
+                       bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
+                       free((caddr_t)ifnet_addrs, M_IFADDR);
+               }
+               ifnet_addrs = q;
+       }
+       /* XXX -- Temporary fix before changing 10 ethernet drivers */
+       if (ifp->if_output == ether_output) {
+               ifp->if_type = IFT_ETHER;
+               ifp->if_addrlen = 6;
+               ifp->if_hdrlen = 14;
+       }
+       /*
+        * create a Link Level name for this device
+        */
+       unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
+       namelen = strlen(ifp->if_name);
+       unitlen = strlen(unitname);
+#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
+       socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
+                              unitlen + namelen + ifp->if_addrlen;
+#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
+       socksize = ROUNDUP(socksize);
+       if (socksize < sizeof(*sdl))
+               socksize = sizeof(*sdl);
+       ifasize = sizeof(*ifa) + 2 * socksize;
+       ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
+       if (ifa == 0)
+               return;
+       ifnet_addrs[if_index - 1] = ifa;
+       bzero((caddr_t)ifa, ifasize);
+       sdl = (struct sockaddr_dl *)(ifa + 1);
+       ifa->ifa_addr = (struct sockaddr *)sdl;
+       ifa->ifa_ifp = ifp;
+       sdl->sdl_len = socksize;
+       sdl->sdl_family = AF_LINK;
+       bcopy(ifp->if_name, sdl->sdl_data, namelen);
+       bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
+       sdl->sdl_nlen = (namelen += unitlen);
+       sdl->sdl_index = ifp->if_index;
+       sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
+       ifa->ifa_netmask = (struct sockaddr *)sdl;
+       sdl->sdl_len = socksize - ifp->if_addrlen;
+       while (namelen != 0)
+               sdl->sdl_data[--namelen] = 0xff;
+       ifa->ifa_next = ifp->if_addrlist;
+       ifa->ifa_rtrequest = link_rtrequest;
+       ifp->if_addrlist = ifa;
+}
+/*
+ * Locate an interface based on a complete address.
+ */
+/*ARGSUSED*/
+struct ifaddr *
+ifa_ifwithaddr(addr)
+       register struct sockaddr *addr;
+{
+       register struct ifnet *ifp;
+       register struct ifaddr *ifa;
+
+#define        equal(a1, a2) \
+  (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
+       for (ifp = ifnet; ifp; ifp = ifp->if_next)
+           for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+               if (ifa->ifa_addr->sa_family != addr->sa_family)
+                       continue;
+               if (equal(addr, ifa->ifa_addr))
+                       return (ifa);
+               if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
+                   equal(ifa->ifa_broadaddr, addr))
+                       return (ifa);
+       }
+       return ((struct ifaddr *)0);
+}
+/*
+ * Locate the point to point interface with a given destination address.
+ */
+/*ARGSUSED*/
+struct ifaddr *
+ifa_ifwithdstaddr(addr)
+       register struct sockaddr *addr;
+{
+       register struct ifnet *ifp;
+       register struct ifaddr *ifa;
+
+       for (ifp = ifnet; ifp; ifp = ifp->if_next) 
+           if (ifp->if_flags & IFF_POINTOPOINT)
+               for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+                       if (ifa->ifa_addr->sa_family != addr->sa_family)
+                               continue;
+                       if (equal(addr, ifa->ifa_dstaddr))
+                               return (ifa);
+       }
+       return ((struct ifaddr *)0);
+}
+
+/*
+ * Find an interface on a specific network.  If many, choice
+ * is first found.
+ */
+struct ifaddr *
+ifa_ifwithnet(addr)
+       struct sockaddr *addr;
+{
+       register struct ifnet *ifp;
+       register struct ifaddr *ifa;
+       u_int af = addr->sa_family;
+
+       if (af >= AF_MAX)
+               return (0);
+       if (af == AF_LINK) {
+           register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
+           if (sdl->sdl_index && sdl->sdl_index <= if_index)
+               return (ifnet_addrs[sdl->sdl_index - 1]);
+       }
+       for (ifp = ifnet; ifp; ifp = ifp->if_next)
+           for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+               register char *cp, *cp2, *cp3;
+               register char *cplim;
+               if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
+                       continue;
+               cp = addr->sa_data;
+               cp2 = ifa->ifa_addr->sa_data;
+               cp3 = ifa->ifa_netmask->sa_data;
+               cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
+               for (; cp3 < cplim; cp3++)
+                       if ((*cp++ ^ *cp2++) & *cp3)
+                               break;
+               if (cp3 == cplim)
+                       return (ifa);
+           }
+       return ((struct ifaddr *)0);
+}
+
+/*
+ * Find an interface using a specific address family
+ */
+struct ifaddr *
+ifa_ifwithaf(af)
+       register int af;
+{
+       register struct ifnet *ifp;
+       register struct ifaddr *ifa;
+
+       for (ifp = ifnet; ifp; ifp = ifp->if_next)
+           for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+               if (ifa->ifa_addr->sa_family == af)
+                       return (ifa);
+       return ((struct ifaddr *)0);
+}
+
+/*
+ * Find an interface address specific to an interface best matching
+ * a given address.
+ */
+struct ifaddr *
+ifaof_ifpforaddr(addr, ifp)
+       struct sockaddr *addr;
+       register struct ifnet *ifp;
+{
+       register struct ifaddr *ifa;
+       register char *cp, *cp2, *cp3;
+       register char *cplim;
+       struct ifaddr *ifa_maybe = 0;
+       u_int af = addr->sa_family;
+
+       if (af >= AF_MAX)
+               return (0);
+       for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+               if (ifa->ifa_addr->sa_family != af)
+                       continue;
+               ifa_maybe = ifa;
+               if (ifa->ifa_netmask == 0) {
+                       if (equal(addr, ifa->ifa_addr) ||
+                           (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
+                               return (ifa);
+                       continue;
+               }
+               cp = addr->sa_data;
+               cp2 = ifa->ifa_addr->sa_data;
+               cp3 = ifa->ifa_netmask->sa_data;
+               cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
+               for (; cp3 < cplim; cp3++)
+                       if ((*cp++ ^ *cp2++) & *cp3)
+                               break;
+               if (cp3 == cplim)
+                       return (ifa);
+       }
+       return (ifa_maybe);
+}
+#include "route.h"
+/*
+ * Default action when installing a route with a Link Level gateway.
+ * Lookup an appropriate real ifa to point to.
+ * This should be moved to /sys/net/link.c eventually.
+ */
+link_rtrequest(cmd, rt, sa)
+register struct rtentry *rt;
+struct sockaddr *sa;
+{
+       register struct ifaddr *ifa;
+       struct sockaddr *dst;
+       struct ifnet *ifp, *oldifnet = ifnet;
+
+       if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
+           ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
+               return;
+       if (ifa = ifaof_ifpforaddr(dst, ifp)) {
+               rt->rt_ifa = ifa;
+               if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
+                       ifa->ifa_rtrequest(cmd, rt, sa);
+       }
+}
+
+/*
+ * Mark an interface down and notify protocols of
+ * the transition.
+ * NOTE: must be called at splnet or eqivalent.
+ */
+if_down(ifp)
+       register struct ifnet *ifp;
+{
+       register struct ifaddr *ifa;
+
+       ifp->if_flags &= ~IFF_UP;
+       for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+               pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
+       if_qflush(&ifp->if_snd);
+}
+
+/*
+ * Flush an interface queue.
+ */
+if_qflush(ifq)
+       register struct ifqueue *ifq;
+{
+       register struct mbuf *m, *n;
+
+       n = ifq->ifq_head;
+       while (m = n) {
+               n = m->m_act;
+               m_freem(m);
+       }
+       ifq->ifq_head = 0;
+       ifq->ifq_tail = 0;
+       ifq->ifq_len = 0;
+}
+
+/*
+ * Handle interface watchdog timer routines.  Called
+ * from softclock, we decrement timers (if set) and
+ * call the appropriate interface routine on expiration.
+ */
+if_slowtimo()
+{
+       register struct ifnet *ifp;
+       int s = splimp();
+
+       for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+               if (ifp->if_timer == 0 || --ifp->if_timer)
+                       continue;
+               if (ifp->if_watchdog)
+                       (*ifp->if_watchdog)(ifp->if_unit);
+       }
+       splx(s);
+       timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
+}
+
+/*
+ * Map interface name to
+ * interface structure pointer.
+ */
+struct ifnet *
+ifunit(name)
+       register char *name;
+{
+       register char *cp;
+       register struct ifnet *ifp;
+       int unit;
+       unsigned len;
+       char *ep, c;
+
+       for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
+               if (*cp >= '0' && *cp <= '9')
+                       break;
+       if (*cp == '\0' || cp == name + IFNAMSIZ)
+               return ((struct ifnet *)0);
+       /*
+        * Save first char of unit, and pointer to it,
+        * so we can put a null there to avoid matching
+        * initial substrings of interface names.
+        */
+       len = cp - name + 1;
+       c = *cp;
+       ep = cp;
+       for (unit = 0; *cp >= '0' && *cp <= '9'; )
+               unit = unit * 10 + *cp++ - '0';
+       *ep = 0;
+       for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+               if (bcmp(ifp->if_name, name, len))
+                       continue;
+               if (unit == ifp->if_unit)
+                       break;
+       }
+       *ep = c;
+       return (ifp);
+}
+
+/*
+ * Interface ioctls.
+ */
+ifioctl(so, cmd, data, p)
+       struct socket *so;
+       int cmd;
+       caddr_t data;
+       struct proc *p;
+{
+       register struct ifnet *ifp;
+       register struct ifreq *ifr;
+       int error;
+
+       switch (cmd) {
+
+       case SIOCGIFCONF:
+       case OSIOCGIFCONF:
+               return (ifconf(cmd, data));
+
+#if defined(INET) && NETHER > 0
+       case SIOCSARP:
+       case SIOCDARP:
+               if (error = suser(p->p_ucred, &p->p_acflag))
+                       return (error);
+               /* FALL THROUGH */
+       case SIOCGARP:
+       case OSIOCGARP:
+               return (arpioctl(cmd, data));
+#endif
+       }
+       ifr = (struct ifreq *)data;
+       ifp = ifunit(ifr->ifr_name);
+       if (ifp == 0)
+               return (ENXIO);
+       switch (cmd) {
+
+       case SIOCGIFFLAGS:
+               ifr->ifr_flags = ifp->if_flags;
+               break;
+
+       case SIOCGIFMETRIC:
+               ifr->ifr_metric = ifp->if_metric;
+               break;
+
+       case SIOCSIFFLAGS:
+               if (error = suser(p->p_ucred, &p->p_acflag))
+                       return (error);
+               if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
+                       int s = splimp();
+                       if_down(ifp);
+                       splx(s);
+               }
+               ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
+                       (ifr->ifr_flags &~ IFF_CANTCHANGE);
+               if (ifp->if_ioctl)
+                       (void) (*ifp->if_ioctl)(ifp, cmd, data);
+               break;
+
+       case SIOCSIFMETRIC:
+               if (error = suser(p->p_ucred, &p->p_acflag))
+                       return (error);
+               ifp->if_metric = ifr->ifr_metric;
+               break;
+
+       default:
+               if (so->so_proto == 0)
+                       return (EOPNOTSUPP);
+#ifndef COMPAT_43
+               return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
+                       cmd, data, ifp));
+#else
+           {
+               int ocmd = cmd;
+
+               switch (cmd) {
+
+               case SIOCSIFDSTADDR:
+               case SIOCSIFADDR:
+               case SIOCSIFBRDADDR:
+               case SIOCSIFNETMASK:
+#if BYTE_ORDER != BIG_ENDIAN
+                       if (ifr->ifr_addr.sa_family == 0 &&
+                           ifr->ifr_addr.sa_len < 16) {
+                               ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
+                               ifr->ifr_addr.sa_len = 16;
+                       }
+#else
+                       if (ifr->ifr_addr.sa_len == 0)
+                               ifr->ifr_addr.sa_len = 16;
+#endif
+                       break;
+
+               case OSIOCGIFADDR:
+                       cmd = SIOCGIFADDR;
+                       break;
+
+               case OSIOCGIFDSTADDR:
+                       cmd = SIOCGIFDSTADDR;
+                       break;
+
+               case OSIOCGIFBRDADDR:
+                       cmd = SIOCGIFBRDADDR;
+                       break;
+
+               case OSIOCGIFNETMASK:
+                       cmd = SIOCGIFNETMASK;
+               }
+               error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
+                                                           cmd, data, ifp));
+               switch (ocmd) {
+
+               case OSIOCGIFADDR:
+               case OSIOCGIFDSTADDR:
+               case OSIOCGIFBRDADDR:
+               case OSIOCGIFNETMASK:
+                       *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
+               }
+               return (error);
+
+           }
+#endif
+       }
+       return (0);
+}
+
+/*
+ * Return interface configuration
+ * of system.  List may be used
+ * in later ioctl's (above) to get
+ * other information.
+ */
+/*ARGSUSED*/
+ifconf(cmd, data)
+       int cmd;
+       caddr_t data;
+{
+       register struct ifconf *ifc = (struct ifconf *)data;
+       register struct ifnet *ifp = ifnet;
+       register struct ifaddr *ifa;
+       register char *cp, *ep;
+       struct ifreq ifr, *ifrp;
+       int space = ifc->ifc_len, error = 0;
+
+       ifrp = ifc->ifc_req;
+       ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
+       for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
+               bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
+               for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
+                       ;
+               *cp++ = '0' + ifp->if_unit; *cp = '\0';
+               if ((ifa = ifp->if_addrlist) == 0) {
+                       bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
+                       error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
+                       if (error)
+                               break;
+                       space -= sizeof (ifr), ifrp++;
+               } else 
+                   for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
+                       register struct sockaddr *sa = ifa->ifa_addr;
+#ifdef COMPAT_43
+                       if (cmd == OSIOCGIFCONF) {
+                               struct osockaddr *osa =
+                                        (struct osockaddr *)&ifr.ifr_addr;
+                               ifr.ifr_addr = *sa;
+                               osa->sa_family = sa->sa_family;
+                               error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+                                               sizeof (ifr));
+                               ifrp++;
+                       } else
+#endif
+                       if (sa->sa_len <= sizeof(*sa)) {
+                               ifr.ifr_addr = *sa;
+                               error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+                                               sizeof (ifr));
+                               ifrp++;
+                       } else {
+                               space -= sa->sa_len - sizeof(*sa);
+                               if (space < sizeof (ifr))
+                                       break;
+                               error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+                                               sizeof (ifr.ifr_name));
+                               if (error == 0)
+                                   error = copyout((caddr_t)sa,
+                                     (caddr_t)&ifrp->ifr_addr, sa->sa_len);
+                               ifrp = (struct ifreq *)
+                                       (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
+                       }
+                       if (error)
+                               break;
+                       space -= sizeof (ifr);
+               }
+       }
+       ifc->ifc_len -= space;
+       return (error);
+}
+
+static char *
+sprint_d(n, buf, buflen)
+       u_int n;
+       char *buf;
+       int buflen;
+{
+       register char *cp = buf + buflen - 1;
+
+       *cp = 0;
+       do {
+               cp--;
+               *cp = "0123456789"[n % 10];
+               n /= 10;
+       } while (n != 0);
+       return (cp);
+}
diff --git a/usr/src/sys.386bsd/net/if_arp.h b/usr/src/sys.386bsd/net/if_arp.h
new file mode 100644 (file)
index 0000000..355af2a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_arp.h    7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Address Resolution Protocol.
+ *
+ * See RFC 826 for protocol description.  ARP packets are variable
+ * in size; the arphdr structure defines the fixed-length portion.
+ * Protocol type values are the same as those for 10 Mb/s Ethernet.
+ * It is followed by the variable-sized fields ar_sha, arp_spa,
+ * arp_tha and arp_tpa in that order, according to the lengths
+ * specified.  Field names used correspond to RFC 826.
+ */
+struct arphdr {
+       u_short ar_hrd;         /* format of hardware address */
+#define ARPHRD_ETHER   1       /* ethernet hardware address */
+       u_short ar_pro;         /* format of protocol address */
+       u_char  ar_hln;         /* length of hardware address */
+       u_char  ar_pln;         /* length of protocol address */
+       u_short ar_op;          /* one of: */
+#define        ARPOP_REQUEST   1       /* request to resolve address */
+#define        ARPOP_REPLY     2       /* response to previous request */
+/*
+ * The remaining fields are variable in size,
+ * according to the sizes above.
+ */
+/*     u_char  ar_sha[];       /* sender hardware address */
+/*     u_char  ar_spa[];       /* sender protocol address */
+/*     u_char  ar_tha[];       /* target hardware address */
+/*     u_char  ar_tpa[];       /* target protocol address */
+};
+
+/*
+ * ARP ioctl request
+ */
+struct arpreq {
+       struct  sockaddr arp_pa;                /* protocol address */
+       struct  sockaddr arp_ha;                /* hardware address */
+       int     arp_flags;                      /* flags */
+};
+/*  arp_flags and at_flags field values */
+#define        ATF_INUSE       0x01    /* entry in use */
+#define ATF_COM                0x02    /* completed entry (enaddr valid) */
+#define        ATF_PERM        0x04    /* permanent entry */
+#define        ATF_PUBL        0x08    /* publish entry (respond for other host) */
+#define        ATF_USETRAILERS 0x10    /* has requested trailers */
diff --git a/usr/src/sys.386bsd/net/if_dl.h b/usr/src/sys.386bsd/net/if_dl.h
new file mode 100644 (file)
index 0000000..65a4109
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_dl.h     7.2 (Berkeley) 2/22/91
+ */
+
+/* 
+ * A Link-Level Sockaddr may specify the interface in one of two
+ * ways: either by means of a system-provided index number (computed
+ * anew and possibly differently on every reboot), or by a human-readable
+ * string such as "il0" (for managerial convenience).
+ * 
+ * Census taking actions, such as something akin to SIOCGCONF would return
+ * both the index and the human name.
+ * 
+ * High volume transactions (such as giving a link-level ``from'' address
+ * in a recvfrom or recvmsg call) may be likely only to provide the indexed
+ * form, (which requires fewer copy operations and less space).
+ * 
+ * The form and interpretation  of the link-level address is purely a matter
+ * of convention between the device driver and its consumers; however, it is
+ * expected that all drivers for an interface of a given if_type will agree.
+ */
+
+/*
+ * Structure of a Link-Level sockaddr:
+ */
+struct sockaddr_dl {
+       u_char  sdl_len;        /* Total length of sockaddr */
+       u_char  sdl_family;     /* AF_DLI */
+       u_short sdl_index;      /* if != 0, system given index for interface */
+       u_char  sdl_type;       /* interface type */
+       u_char  sdl_nlen;       /* interface name length, no trailing 0 reqd. */
+       u_char  sdl_alen;       /* link level address length */
+       u_char  sdl_slen;       /* link layer selector length */
+       char    sdl_data[12];   /* minimum work area, can be larger;
+                                  contains both if name and ll address */
+};
+
+#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void   link_addr __P((const char *, struct sockaddr_dl *));
+char   *link_ntoa __P((const struct sockaddr_dl *));
+__END_DECLS
+
+#endif /* !KERNEL */
diff --git a/usr/src/sys.386bsd/net/if_ethersubr.c b/usr/src/sys.386bsd/net/if_ethersubr.c
new file mode 100644 (file)
index 0000000..69e8554
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 1982, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_ethersubr.c      7.13 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "ioctl.h"
+#include "errno.h"
+#include "syslog.h"
+
+#include "if.h"
+#include "netisr.h"
+#include "route.h"
+#include "if_llc.h"
+#include "if_dl.h"
+
+#include "machine/mtpr.h"
+
+#ifdef INET
+#include "../netinet/in.h"
+#include "../netinet/in_var.h"
+#endif
+#include "../netinet/if_ether.h"
+
+#ifdef NS
+#include "../netns/ns.h"
+#include "../netns/ns_if.h"
+#endif
+
+#ifdef ISO
+#include "../netiso/argo_debug.h"
+#include "../netiso/iso.h"
+#include "../netiso/iso_var.h"
+#include "../netiso/iso_snpac.h"
+#endif
+
+u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+extern struct ifnet loif;
+
+/*
+ * Ethernet output routine.
+ * Encapsulate a packet of type family for the local net.
+ * Use trailer local net encapsulation if enough data in first
+ * packet leaves a multiple of 512 bytes of data in remainder.
+ * Assumes that ifp is actually pointer to arpcom structure.
+ */
+ether_output(ifp, m0, dst, rt)
+       register struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+       struct rtentry *rt;
+{
+       short type;
+       int s, error = 0;
+       u_char edst[6];
+       struct in_addr idst;
+       register struct mbuf *m = m0;
+       struct mbuf *mcopy = (struct mbuf *)0;
+       register struct ether_header *eh;
+       int usetrailers, off, len = m->m_pkthdr.len;
+#define        ac ((struct arpcom *)ifp)
+
+       if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+               error = ENETDOWN;
+               goto bad;
+       }
+       ifp->if_lastchange = time;
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET:
+               idst = ((struct sockaddr_in *)dst)->sin_addr;
+               if (!arpresolve(ac, m, &idst, edst, &usetrailers))
+                       return (0);     /* if not yet resolved */
+               if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
+                       mcopy = m_copy(m, 0, (int)M_COPYALL);
+               off = m->m_pkthdr.len - m->m_len;
+               if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
+                   (m->m_flags & M_EXT) == 0 &&
+                   m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
+                       type = ETHERTYPE_TRAIL + (off>>9);
+                       m->m_data -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
+                       len += 2 * sizeof (u_short);
+                       *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
+                       *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
+                       goto gottrailertype;
+               }
+               type = ETHERTYPE_IP;
+               goto gottype;
+#endif
+#ifdef NS
+       case AF_NS:
+               type = ETHERTYPE_NS;
+               bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
+                   (caddr_t)edst, sizeof (edst));
+               if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
+                       return (looutput(ifp, m, dst, rt));
+               if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
+                       mcopy = m_copy(m, 0, (int)M_COPYALL);
+               goto gottype;
+#endif
+#ifdef ISO
+       case AF_ISO: {
+               int     snpalen;
+               struct  llc *l;
+
+       iso_again:
+               if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
+                       if (rt->rt_flags & RTF_GATEWAY) {
+                               if (rt->rt_llinfo) {
+                                       rt = (struct rtentry *)rt->rt_llinfo;
+                                       goto iso_again;
+                               }
+                       } else {
+                               register struct sockaddr_dl *sdl = 
+                                       (struct sockaddr_dl *)rt->rt_gateway;
+                               if (sdl && sdl->sdl_family == AF_LINK
+                                   && sdl->sdl_alen > 0) {
+                                       bcopy(LLADDR(sdl), (char *)edst,
+                                                               sizeof(edst));
+                                       goto iso_resolved;
+                               }
+                       }
+               }
+               if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
+                                       (char *)edst, &snpalen)) > 0)
+                       goto bad; /* Not Resolved */
+       iso_resolved:
+               if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
+                   (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
+                       M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
+                       if (mcopy) {
+                               eh = mtod(mcopy, struct ether_header *);
+                               bcopy((caddr_t)edst,
+                                     (caddr_t)eh->ether_dhost, sizeof (edst));
+                               bcopy((caddr_t)ac->ac_enaddr,
+                                     (caddr_t)eh->ether_shost, sizeof (edst));
+                       }
+               }
+               M_PREPEND(m, 3, M_DONTWAIT);
+               if (m == NULL)
+                       return (0);
+               type = m->m_pkthdr.len;
+               l = mtod(m, struct llc *);
+               l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
+               l->llc_control = LLC_UI;
+               len += 3;
+               IFDEBUG(D_ETHER)
+                       int i;
+                       printf("unoutput: sending pkt to: ");
+                       for (i=0; i<6; i++)
+                               printf("%x ", edst[i] & 0xff);
+                       printf("\n");
+               ENDDEBUG
+               } goto gottype;
+#endif ISO
+#ifdef RMP
+       case AF_RMP:
+               /*
+                *  This is IEEE 802.3 -- the Ethernet `type' field is
+                *  really a `length' field.
+                */
+               type = m->m_len;
+               bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
+               break;
+#endif
+
+       case AF_UNSPEC:
+               eh = (struct ether_header *)dst->sa_data;
+               bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
+               type = eh->ether_type;
+               goto gottype;
+
+       default:
+               printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
+                       dst->sa_family);
+               error = EAFNOSUPPORT;
+               goto bad;
+       }
+
+gottrailertype:
+       /*
+        * Packet to be sent as trailer: move first packet
+        * (control information) to end of chain.
+        */
+       while (m->m_next)
+               m = m->m_next;
+       m->m_next = m0;
+       m = m0->m_next;
+       m0->m_next = 0;
+
+gottype:
+       if (mcopy)
+               (void) looutput(ifp, mcopy, dst, rt);
+       /*
+        * Add local net header.  If no space in first mbuf,
+        * allocate another.
+        */
+       M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
+       if (m == 0) {
+               error = ENOBUFS;
+               goto bad;
+       }
+       eh = mtod(m, struct ether_header *);
+       type = htons((u_short)type);
+       bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
+               sizeof(eh->ether_type));
+       bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
+       bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
+           sizeof(eh->ether_shost));
+       s = splimp();
+       /*
+        * Queue message on interface, and start output if interface
+        * not yet active.
+        */
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               splx(s);
+               error = ENOBUFS;
+               goto bad;
+       }
+       IF_ENQUEUE(&ifp->if_snd, m);
+       if ((ifp->if_flags & IFF_OACTIVE) == 0)
+               (*ifp->if_start)(ifp);
+       splx(s);
+       ifp->if_obytes += len + sizeof (struct ether_header);
+       if (edst[0] & 1)
+               ifp->if_omcasts++;
+       return (error);
+
+bad:
+       if (m)
+               m_freem(m);
+       return (error);
+}
+
+/*
+ * Process a received Ethernet packet;
+ * the packet is in the mbuf chain m without
+ * the ether header, which is provided separately.
+ */
+ether_input(ifp, eh, m)
+       struct ifnet *ifp;
+       register struct ether_header *eh;
+       struct mbuf *m;
+{
+       register struct ifqueue *inq;
+       register struct llc *l;
+       int s;
+
+       ifp->if_lastchange = time;
+       ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
+       if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+           sizeof(etherbroadcastaddr)) == 0)
+               m->m_flags |= M_BCAST;
+       else if (eh->ether_dhost[0] & 1)
+               m->m_flags |= M_MCAST;
+       if (m->m_flags & (M_BCAST|M_MCAST))
+               ifp->if_imcasts++;
+
+       switch (eh->ether_type) {
+#ifdef INET
+       case ETHERTYPE_IP:
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+
+       case ETHERTYPE_ARP:
+               arpinput((struct arpcom *)ifp, m);
+               return;
+#endif
+#ifdef NS
+       case ETHERTYPE_NS:
+               schednetisr(NETISR_NS);
+               inq = &nsintrq;
+               break;
+
+#endif
+       default:
+#ifdef ISO
+               if (eh->ether_type > ETHERMTU)
+                       goto dropanyway;
+               l = mtod(m, struct llc *);
+               switch (l->llc_control) {
+               case LLC_UI:
+               /* LLC_UI_P forbidden in class 1 service */
+                   if ((l->llc_dsap == LLC_ISO_LSAP) &&
+                       (l->llc_ssap == LLC_ISO_LSAP)) {
+                               /* LSAP for ISO */
+                       if (m->m_pkthdr.len > eh->ether_type)
+                               m_adj(m, eh->ether_type - m->m_pkthdr.len);
+                       m->m_data += 3;         /* XXX */
+                       m->m_len -= 3;          /* XXX */
+                       m->m_pkthdr.len -= 3;   /* XXX */
+                       M_PREPEND(m, sizeof *eh, M_DONTWAIT);
+                       if (m == 0)
+                               return;
+                       *mtod(m, struct ether_header *) = *eh;
+                       IFDEBUG(D_ETHER)
+                           printf("clnp packet");
+                       ENDDEBUG
+                       schednetisr(NETISR_ISO);
+                       inq = &clnlintrq;
+                       break;
+                   }
+                   goto dropanyway;
+
+               case LLC_XID:
+               case LLC_XID_P:
+                   if(m->m_len < 6)
+                       goto dropanyway;
+                   l->llc_window = 0;
+                   l->llc_fid = 9;
+                   l->llc_class = 1;
+                   l->llc_dsap = l->llc_ssap = 0;
+                   /* Fall through to */
+               case LLC_TEST:
+               case LLC_TEST_P:
+               {
+                   struct sockaddr sa;
+                   register struct ether_header *eh2;
+                   int i;
+                   u_char c = l->llc_dsap;
+                   l->llc_dsap = l->llc_ssap;
+                   l->llc_ssap = c;
+                   if (m->m_flags & (M_BCAST | M_MCAST))
+                       bcopy((caddr_t)ac->ac_enaddr,
+                             (caddr_t)eh->ether_dhost, 6);
+                   sa.sa_family = AF_UNSPEC;
+                   sa.sa_len = sizeof(sa);
+                   eh2 = (struct ether_header *)sa.sa_data;
+                   for (i = 0; i < 6; i++) {
+                       eh2->ether_shost[i] = c = eh->ether_dhost[i];
+                       eh2->ether_dhost[i] = 
+                               eh->ether_dhost[i] = eh->ether_shost[i];
+                       eh->ether_shost[i] = c;
+                   }
+                   ifp->if_output(ifp, m, &sa);
+                   return;
+               }
+               dropanyway:
+               default:
+                   m_freem(m);
+                   return;
+           }
+#else
+           m_freem(m);
+           return;
+#endif ISO
+       }
+
+       s = splimp();
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
+       splx(s);
+}
+
+/*
+ * Convert Ethernet address to printable (loggable) representation.
+ */
+static char digits[] = "0123456789abcdef";
+char *
+ether_sprintf(ap)
+       register u_char *ap;
+{
+       register i;
+       static char etherbuf[18];
+       register char *cp = etherbuf;
+
+       for (i = 0; i < 6; i++) {
+               *cp++ = digits[*ap >> 4];
+               *cp++ = digits[*ap++ & 0xf];
+               *cp++ = ':';
+       }
+       *--cp = 0;
+       return (etherbuf);
+}
diff --git a/usr/src/sys.386bsd/net/if_llc.h b/usr/src/sys.386bsd/net/if_llc.h
new file mode 100644 (file)
index 0000000..e9aebdf
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)if_llc.h   7.2 (Berkeley) 6/28/90
+ */
+
+/*
+ * IEEE 802.2 Link Level Control headers, for use in conjunction with
+ * 802.{3,4,5} media access control methods.
+ *
+ * Headers here do not use bit fields due to shortcommings in many
+ * compilers.
+ */
+
+struct llc {
+       u_char  llc_dsap;
+       u_char  llc_ssap;
+       union {
+           struct {
+               u_char control;
+               u_char format_id;
+               u_char class;
+               u_char window_x2;
+           } type_u;
+           struct {
+               u_char num_snd_x2;
+               u_char num_rcv_x2;
+           } type_i;
+           struct {
+               u_char control;
+               u_char num_rcv_x2;
+           } type_s;
+           struct {
+               u_char control;
+               u_char org_code[3];
+               u_short ether_type;
+           } type_snap;
+       } llc_un;
+};
+#define llc_control llc_un.type_u.control
+#define llc_fid llc_un.type_u.format_id
+#define llc_class llc_un.type_u.class
+#define llc_window llc_un.type_u.window_x2
+
+#define LLC_UI         0x3
+#define LLC_UI_P       0x13
+#define LLC_XID                0xaf
+#define LLC_XID_P      0xbf
+#define LLC_TEST       0xe3
+#define LLC_TEST_P     0xf3
+
+#define LLC_ISO_LSAP   0xfe
+#define LLC_SNAP_LSAP  0xaa
diff --git a/usr/src/sys.386bsd/net/if_loop.c b/usr/src/sys.386bsd/net/if_loop.c
new file mode 100644 (file)
index 0000000..5ec4aac
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_loop.c   7.13 (Berkeley) 4/26/91
+ */
+
+/*
+ * Loopback interface driver for protocol testing and timing.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "errno.h"
+#include "ioctl.h"
+
+#include "../net/if.h"
+#include "../net/if_types.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+
+#include "machine/mtpr.h"
+
+#ifdef INET
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#endif
+
+#ifdef NS
+#include "../netns/ns.h"
+#include "../netns/ns_if.h"
+#endif
+
+#ifdef ISO
+#include "../netiso/iso.h"
+#include "../netiso/iso_var.h"
+#endif
+
+#define        LOMTU   (1024+512)
+
+struct ifnet loif;
+int    looutput(), loioctl();
+
+loattach()
+{
+       register struct ifnet *ifp = &loif;
+
+       ifp->if_name = "lo";
+       ifp->if_mtu = LOMTU;
+       ifp->if_flags = IFF_LOOPBACK;
+       ifp->if_ioctl = loioctl;
+       ifp->if_output = looutput;
+       ifp->if_type = IFT_LOOP;
+       ifp->if_hdrlen = 0;
+       ifp->if_addrlen = 0;
+       if_attach(ifp);
+}
+
+looutput(ifp, m, dst, rt)
+       struct ifnet *ifp;
+       register struct mbuf *m;
+       struct sockaddr *dst;
+       register struct rtentry *rt;
+{
+       int s, isr;
+       register struct ifqueue *ifq = 0;
+
+       if ((m->m_flags & M_PKTHDR) == 0)
+               panic("looutput no HDR");
+       m->m_pkthdr.rcvif = ifp;
+
+       if (rt && rt->rt_flags & RTF_REJECT) {
+               m_freem(m);
+               return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
+       }
+       ifp->if_opackets++;
+       ifp->if_obytes += m->m_pkthdr.len;
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET:
+               ifq = &ipintrq;
+               isr = NETISR_IP;
+               break;
+#endif
+#ifdef NS
+       case AF_NS:
+               ifq = &nsintrq;
+               isr = NETISR_NS;
+               break;
+#endif
+#ifdef ISO
+       case AF_ISO:
+               ifq = &clnlintrq;
+               isr = NETISR_ISO;
+               break;
+#endif
+       default:
+               printf("lo%d: can't handle af%d\n", ifp->if_unit,
+                       dst->sa_family);
+               m_freem(m);
+               return (EAFNOSUPPORT);
+       }
+       s = splimp();
+       if (IF_QFULL(ifq)) {
+               IF_DROP(ifq);
+               m_freem(m);
+               splx(s);
+               return (ENOBUFS);
+       }
+       IF_ENQUEUE(ifq, m);
+       schednetisr(isr);
+       ifp->if_ipackets++;
+       ifp->if_ibytes += m->m_pkthdr.len;
+       splx(s);
+       return (0);
+}
+
+/* ARGSUSED */
+lortrequest(cmd, rt, sa)
+struct rtentry *rt;
+struct sockaddr *sa;
+{
+       if (rt)
+               rt->rt_rmx.rmx_mtu = LOMTU;
+}
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+loioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       register struct ifaddr *ifa;
+       int error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               ifa = (struct ifaddr *)data;
+               if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
+                       ifa->ifa_rtrequest = lortrequest;
+               /*
+                * Everything else is done at a higher level.
+                */
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       return (error);
+}
diff --git a/usr/src/sys.386bsd/net/if_slvar.h b/usr/src/sys.386bsd/net/if_slvar.h
new file mode 100644 (file)
index 0000000..076c051
--- /dev/null
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_slvar.h  7.7 (Berkeley) 5/7/91
+ *
+ * $Header: if_slvar.h,v 1.3 89/05/31 02:25:18 van Exp $
+ */
+
+/*
+ * Definitions for SLIP interface data structures
+ * 
+ * (This exists so programs like slstats can get at the definition
+ *  of sl_softc.)
+ */
+struct sl_softc {
+       struct  ifnet sc_if;            /* network-visible interface */
+       struct  ifqueue sc_fastq;       /* interactive output queue */
+       struct  tty *sc_ttyp;           /* pointer to tty structure */
+       u_char  *sc_mp;                 /* pointer to next available buf char */
+       u_char  *sc_ep;                 /* pointer to last available buf char */
+       u_char  *sc_buf;                /* input buffer */
+       u_int   sc_flags;               /* see below */
+       u_int   sc_escape;      /* =1 if last char input was FRAME_ESCAPE */
+       u_int   sc_bytessent;
+       u_int   sc_bytesrcvd;
+       long    sc_lasttime;            /* last time a char arrived */
+       long    sc_starttime;           /* last time a char arrived */
+       long    sc_abortcount;          /* number of abort esacpe chars */
+#ifdef INET                            /* XXX */
+       struct  slcompress sc_comp;     /* tcp compression data */
+#endif
+};
+
+/* visible flags */
+#define        SC_COMPRESS     0x0002          /* compress TCP traffic */
+#define        SC_NOICMP       0x0004          /* supress ICMP traffic */
+#define        SC_AUTOCOMP     0x0008          /* auto-enable TCP compression */
+/* internal flags (should be separate) */
+#define        SC_ABORT        0x10000         /* have been sent an abort request */
+
+/* this stuff doesn't belong here... */
+#define        SLIOCGFLAGS     _IOR('t', 90, int)      /* get configuration flags */
+#define        SLIOCSFLAGS     _IOW('t', 89, int)      /* set configuration flags */
+#define        SLIOCGUNIT      _IOR('t', 88, int)      /* get slip unit number */
diff --git a/usr/src/sys.386bsd/net/if_types.h b/usr/src/sys.386bsd/net/if_types.h
new file mode 100644 (file)
index 0000000..70b8195
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_types.h  7.3 (Berkeley) 6/28/90
+ */
+
+
+/* interface types for benefit of parsing media address headers */
+#define IFT_OTHER      0x1             /* none of the following */
+#define IFT_1822       0x2             /* old-style arpanet imp */
+#define IFT_HDH1822    0x3             /* HDH arpanet imp */
+#define IFT_X25DDN     0x4             /* x25 to imp */
+#define IFT_X25                0x5             /* PDN X25 interface */
+#define        IFT_ETHER       0x6             /* Ethernet I or II */
+#define        IFT_ISO88023    0x7             /* CMSA CD */
+#define        IFT_ISO88024    0x8             /* Token Bus */
+#define        IFT_ISO88025    0x9             /* Token Ring */
+#define        IFT_ISO88026    0xa             /* MAN */
+#define        IFT_STARLAN     0xb
+#define        IFT_P10         0xc             /* Proteon 10MBit ring */
+#define        IFT_P80         0xd             /* Proteon 10MBit ring */
+#define IFT_HY         0xe             /* Hyperchannel */
+#define IFT_FDDI       0xf
+#define IFT_LAPB       0x10
+#define IFT_SDLC       0x11
+#define IFT_T1         0x12
+#define IFT_CEPT       0x13
+#define IFT_ISDNBASIC  0x14
+#define IFT_ISDNPRIMARY        0x15
+#define IFT_PTPSERIAL  0x16
+#define        IFT_LOOP        0x18            /* loopback */
+#define IFT_EON                0x19            /* ISO over IP */
+#define        IFT_XETHER      0x1a            /* obsolete 3MB experimental ethernet */
+#define        IFT_NSIP        0x1b            /* XNS over IP */
+#define        IFT_SLIP        0x1c            /* IP over generic TTY */
diff --git a/usr/src/sys.386bsd/net/netisr.h b/usr/src/sys.386bsd/net/netisr.h
new file mode 100644 (file)
index 0000000..534c68c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1980, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)netisr.h    7.8 (Berkeley) 5/7/91
+ */
+
+/*
+ * The networking code runs off software interrupts.
+ *
+ * You can switch into the network by doing splnet() and return by splx().
+ * The software interrupt level for the network is higher than the software
+ * level for the clock (so you can enter the network in routines called
+ * at timeout time).
+ */
+#if defined(vax) || defined(tahoe)
+#define        setsoftnet()    mtpr(SIRR, 12)
+#endif
+
+/*
+ * Each ``pup-level-1'' input queue has a bit in a ``netisr'' status
+ * word which is used to de-multiplex a single software
+ * interrupt used for scheduling the network code to calls
+ * on the lowest level routine of each protocol.
+ */
+#define        NETISR_RAW      0               /* same as AF_UNSPEC */
+#define        NETISR_IP       2               /* same as AF_INET */
+#define        NETISR_IMP      3               /* same as AF_IMPLINK */
+#define        NETISR_NS       6               /* same as AF_NS */
+#define        NETISR_ISO      7               /* same as AF_ISO */
+#define        NETISR_CCITT    10              /* same as AF_CCITT */
+
+#define        schednetisr(anisr)      { netisr |= 1<<(anisr); setsoftnet(); }
+
+#ifdef i386
+/* XXX Temporary -- soon to vanish - wfj */
+#define        NETISR_SCLK     11              /* softclock */
+#define        NETISR_AST      12              /* ast -- resched */
+
+#undef schednetisr
+#define        schednetisr(anisr)      {\
+       if(netisr == 0) { \
+               softem++; \
+       } \
+       netisr |= 1<<(anisr); \
+}
+#ifndef LOCORE
+#ifdef KERNEL
+int    softem; 
+#endif
+#endif
+#endif /* i386 */
+
+#ifndef LOCORE
+#ifdef KERNEL
+int    netisr;                         /* scheduling bits for network */
+#endif
+#endif
diff --git a/usr/src/sys.386bsd/net/radix.c b/usr/src/sys.386bsd/net/radix.c
new file mode 100644 (file)
index 0000000..5f3df88
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 1988, 1989  Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)radix.c     7.9 (Berkeley) 2/4/91
+ */
+
+/*
+ * Routines to build and maintain radix trees for routing lookups.
+ */
+#ifndef RNF_NORMAL
+#include "param.h"
+#include "radix.h"
+#include "malloc.h"
+#define        M_DONTWAIT M_NOWAIT
+#endif
+struct radix_node_head *mask_rnhead;
+#define rn_maskhead mask_rnhead->rnh_treetop
+struct radix_mask *rn_mkfreelist;
+struct radix_node_head *radix_node_head;
+#undef Bcmp
+#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))
+/*
+ * The data structure for the keys is a radix tree with one way
+ * branching removed.  The index rn_b at an internal node n represents a bit
+ * position to be tested.  The tree is arranged so that all descendants
+ * of a node n have keys whose bits all agree up to position rn_b - 1.
+ * (We say the index of n is rn_b.)
+ *
+ * There is at least one descendant which has a one bit at position rn_b,
+ * and at least one with a zero there.
+ *
+ * A route is determined by a pair of key and mask.  We require that the
+ * bit-wise logical and of the key and mask to be the key.
+ * We define the index of a route to associated with the mask to be
+ * the first bit number in the mask where 0 occurs (with bit number 0
+ * representing the highest order bit).
+ * 
+ * We say a mask is normal if every bit is 0, past the index of the mask.
+ * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b,
+ * and m is a normal mask, then the route applies to every descendant of n.
+ * If the index(m) < rn_b, this implies the trailing last few bits of k
+ * before bit b are all 0, (and hence consequently true of every descendant
+ * of n), so the route applies to all descendants of the node as well.
+ *
+ * The present version of the code makes no use of normal routes,
+ * but similar logic shows that a non-normal mask m such that
+ * index(m) <= index(n) could potentially apply to many children of n.
+ * Thus, for each non-host route, we attach its mask to a list at an internal
+ * node as high in the tree as we can go. 
+ */
+
+struct radix_node *
+rn_search(v, head)
+       struct radix_node *head;
+       register caddr_t v;
+{
+       register struct radix_node *x;
+
+       for (x = head; x->rn_b >= 0;) {
+               if (x->rn_bmask & v[x->rn_off])
+                       x = x->rn_r;
+               else
+                       x = x->rn_l;
+       }
+       return x;
+};
+
+struct radix_node *
+rn_search_m(v, head, m)
+       struct radix_node *head;
+       register caddr_t v, m;
+{
+       register struct radix_node *x;
+
+       for (x = head; x->rn_b >= 0;) {
+               if ((x->rn_bmask & m[x->rn_off]) &&
+                   (x->rn_bmask & v[x->rn_off]))
+                       x = x->rn_r;
+               else
+                       x = x->rn_l;
+       }
+       return x;
+};
+
+
+static int gotOddMasks;
+static char maskedKey[MAXKEYLEN];
+
+struct radix_node *
+rn_match(v, head)
+       struct radix_node *head;
+       caddr_t v;
+{
+       register struct radix_node *t = head, *x;
+       register caddr_t cp = v, cp2, cp3;
+       caddr_t cplim, mstart;
+       struct radix_node *saved_t;
+       int off = t->rn_off, vlen = *(u_char *)cp, matched_off;
+
+       /*
+        * Open code rn_search(v, head) to avoid overhead of extra
+        * subroutine call.
+        */
+       for (; t->rn_b >= 0; ) {
+               if (t->rn_bmask & cp[t->rn_off])
+                       t = t->rn_r;
+               else
+                       t = t->rn_l;
+       }
+       /*
+        * See if we match exactly as a host destination
+        */
+       cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
+       for (; cp < cplim; cp++, cp2++)
+               if (*cp != *cp2)
+                       goto on1;
+       /*
+        * This extra grot is in case we are explicitly asked
+        * to look up the default.  Ugh!
+        */
+       if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey)
+               t = t->rn_dupedkey;
+       return t;
+on1:
+       matched_off = cp - v;
+       saved_t = t;
+       do {
+           if (t->rn_mask) {
+               /*
+                * Even if we don't match exactly as a hosts;
+                * we may match if the leaf we wound up at is
+                * a route to a net.
+                */
+               cp3 = matched_off + t->rn_mask;
+               cp2 = matched_off + t->rn_key;
+               for (; cp < cplim; cp++)
+                       if ((*cp2++ ^ *cp) & *cp3++)
+                               break;
+               if (cp == cplim)
+                       return t;
+               cp = matched_off + v;
+           }
+       } while (t = t->rn_dupedkey);
+       t = saved_t;
+       /* start searching up the tree */
+       do {
+               register struct radix_mask *m;
+               t = t->rn_p;
+               if (m = t->rn_mklist) {
+                       /*
+                        * After doing measurements here, it may
+                        * turn out to be faster to open code
+                        * rn_search_m here instead of always
+                        * copying and masking.
+                        */
+                       off = min(t->rn_off, matched_off);
+                       mstart = maskedKey + off;
+                       do {
+                               cp2 = mstart;
+                               cp3 = m->rm_mask + off;
+                               for (cp = v + off; cp < cplim;)
+                                       *cp2++ =  *cp++ & *cp3++;
+                               x = rn_search(maskedKey, t);
+                               while (x && x->rn_mask != m->rm_mask)
+                                       x = x->rn_dupedkey;
+                               if (x &&
+                                   (Bcmp(mstart, x->rn_key + off,
+                                       vlen - off) == 0))
+                                           return x;
+                       } while (m = m->rm_mklist);
+               }
+       } while (t != head);
+       return 0;
+};
+               
+#ifdef RN_DEBUG
+int    rn_nodenum;
+struct radix_node *rn_clist;
+int    rn_saveinfo;
+#endif
+
+struct radix_node *
+rn_newpair(v, b, nodes)
+       caddr_t v;
+       struct radix_node nodes[2];
+{
+       register struct radix_node *tt = nodes, *t = tt + 1;
+       t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7);
+       t->rn_l = tt; t->rn_off = b >> 3;
+       tt->rn_b = -1; tt->rn_key = v; tt->rn_p = t;
+       tt->rn_flags = t->rn_flags = RNF_ACTIVE;
+#ifdef RN_DEBUG
+       tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
+       tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
+#endif
+       return t;
+}
+
+int rn_debug =  1;
+struct radix_node *
+rn_insert(v, head, dupentry, nodes)
+       caddr_t v;
+       struct radix_node *head;
+       int *dupentry;
+       struct radix_node nodes[2];
+{
+       int head_off = head->rn_off, vlen = (int)*((u_char *)v);
+       register struct radix_node *t = rn_search(v, head);
+       register caddr_t cp = v + head_off;
+       register int b;
+       struct radix_node *tt;
+       /*
+        *find first bit at which v and t->rn_key differ
+        */
+    {
+       register caddr_t cp2 = t->rn_key + head_off;
+       register int cmp_res;
+       caddr_t cplim = v + vlen;
+
+       while (cp < cplim)
+               if (*cp2++ != *cp++)
+                       goto on1;
+       *dupentry = 1;
+       return t;
+on1:
+       *dupentry = 0;
+       cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
+       for (b = (cp - v) << 3; cmp_res; b--)
+               cmp_res >>= 1;
+    }
+    {
+       register struct radix_node *p, *x = head;
+       cp = v;
+       do {
+               p = x;
+               if (cp[x->rn_off] & x->rn_bmask) 
+                       x = x->rn_r;
+               else x = x->rn_l;
+       } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */
+#ifdef RN_DEBUG
+       if (rn_debug)
+               printf("Going In:\n"), traverse(p);
+#endif
+       t = rn_newpair(v, b, nodes); tt = t->rn_l;
+       if ((cp[p->rn_off] & p->rn_bmask) == 0)
+               p->rn_l = t;
+       else
+               p->rn_r = t;
+       x->rn_p = t; t->rn_p = p; /* frees x, p as temp vars below */
+       if ((cp[t->rn_off] & t->rn_bmask) == 0) {
+               t->rn_r = x;
+       } else {
+               t->rn_r = tt; t->rn_l = x;
+       }
+#ifdef RN_DEBUG
+       if (rn_debug)
+               printf("Coming out:\n"), traverse(p);
+#endif
+    }
+       return (tt);
+}
+
+struct radix_node *
+rn_addmask(netmask, search, skip)
+caddr_t netmask;
+{
+       register struct radix_node *x;
+       register caddr_t cp, cplim;
+       register int b, mlen, j;
+       int maskduplicated;
+
+       mlen = *(u_char *)netmask;
+       if (search) {
+               x = rn_search(netmask, rn_maskhead);
+               mlen = *(u_char *)netmask;
+               if (Bcmp(netmask, x->rn_key, mlen) == 0)
+                       return (x);
+       }
+       R_Malloc(x, struct radix_node *, MAXKEYLEN + 2 * sizeof (*x));
+       if (x == 0)
+               return (0);
+       Bzero(x, MAXKEYLEN + 2 * sizeof (*x));
+       cp = (caddr_t)(x + 2);
+       Bcopy(netmask, cp, mlen);
+       netmask = cp;
+       x = rn_insert(netmask, rn_maskhead, &maskduplicated, x);
+       /*
+        * Calculate index of mask.
+        */
+       cplim = netmask + mlen;
+       for (cp = netmask + skip; cp < cplim; cp++)
+               if (*(u_char *)cp != 0xff)
+                       break;
+       b = (cp - netmask) << 3;
+       if (cp != cplim) {
+               if (*cp != 0) {
+                       gotOddMasks = 1;
+                       for (j = 0x80; j; b++, j >>= 1)  
+                               if ((j & *cp) == 0)
+                                       break;
+               }
+       }
+       x->rn_b = -1 - b;
+       return (x);
+}
+
+struct radix_node *
+rn_addroute(v, netmask, head, treenodes)
+struct radix_node *head;
+       caddr_t netmask, v;
+       struct radix_node treenodes[2];
+{
+       register int j;
+       register caddr_t cp;
+       register struct radix_node *t, *x, *tt;
+       short b = 0, b_leaf;
+       int vlen = *(u_char *)v, mlen, keyduplicated;
+       caddr_t cplim; unsigned char *maskp;
+       struct radix_mask *m, **mp;
+       struct radix_node *saved_tt;
+
+       /*
+        * In dealing with non-contiguous masks, there may be
+        * many different routes which have the same mask.
+        * We will find it useful to have a unique pointer to
+        * the mask to speed avoiding duplicate references at
+        * nodes and possibly save time in calculating indices.
+        */
+       if (netmask)  {
+               x = rn_search(netmask, rn_maskhead);
+               mlen = *(u_char *)netmask;
+               if (Bcmp(netmask, x->rn_key, mlen) != 0) {
+                       x = rn_addmask(netmask, 0, head->rn_off);
+                       if (x == 0)
+                               return (0);
+               }
+               netmask = x->rn_key;
+               b = -1 - x->rn_b;
+       }
+       /*
+        * Deal with duplicated keys: attach node to previous instance
+        */
+       saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
+       if (keyduplicated) {
+               do {
+                       if (tt->rn_mask == netmask)
+                               return (0);
+                       t = tt;
+               } while (tt = tt->rn_dupedkey);
+               /*
+                * If the mask is not duplicated, we wouldn't
+                * find it among possible duplicate key entries
+                * anyway, so the above test doesn't hurt.
+                *
+                * XXX: we really ought to sort the masks
+                * for a duplicated key the same way as in a masklist.
+                * It is an unfortunate pain having to relocate
+                * the head of the list.
+                */
+               t->rn_dupedkey = tt = treenodes;
+#ifdef RN_DEBUG
+               t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
+               tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
+#endif
+               t = saved_tt;
+               tt->rn_key = (caddr_t) v;
+               tt->rn_b = -1;
+               tt->rn_flags = t->rn_flags & ~RNF_ROOT;
+       }
+       /*
+        * Put mask in tree.
+        */
+       if (netmask) {
+               tt->rn_mask = netmask;
+               tt->rn_b = x->rn_b;
+       }
+       t = saved_tt->rn_p;
+       b_leaf = -1 - t->rn_b;
+       if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r;
+       /* Promote general routes from below */
+       if (x->rn_b < 0) { 
+               if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) {
+                       MKGet(m);
+                       if (m) {
+                               Bzero(m, sizeof *m);
+                               m->rm_b = x->rn_b;
+                               m->rm_mask = x->rn_mask;
+                               x->rn_mklist = t->rn_mklist = m;
+                       }
+               }
+       } else if (x->rn_mklist) {
+               /*
+                * Skip over masks whose index is > that of new node
+                */
+               for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist)
+                       if (m->rm_b >= b_leaf)
+                               break;
+               t->rn_mklist = m; *mp = 0;
+       }
+       /* Add new route to highest possible ancestor's list */
+       if ((netmask == 0) || (b > t->rn_b ))
+               return tt; /* can't lift at all */
+       b_leaf = tt->rn_b;
+       do {
+               x = t;
+               t = t->rn_p;
+       } while (b <= t->rn_b && x != head);
+       /*
+        * Search through routes associated with node to
+        * insert new route according to index.
+        * For nodes of equal index, place more specific
+        * masks first.
+        */
+       cplim = netmask + mlen;
+       for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist) {
+               if (m->rm_b < b_leaf)
+                       continue;
+               if (m->rm_b > b_leaf)
+                       break;
+               if (m->rm_mask == netmask) {
+                       m->rm_refs++;
+                       tt->rn_mklist = m;
+                       return tt;
+               }
+               maskp = (u_char *)m->rm_mask;
+               for (cp = netmask; cp < cplim; cp++)
+                       if (*(u_char *)cp > *maskp++)
+                               goto on2;
+       }
+on2:
+       MKGet(m);
+       if (m == 0) {
+               printf("Mask for route not entered\n");
+               return (tt);
+       }
+       Bzero(m, sizeof *m);
+       m->rm_b = b_leaf;
+       m->rm_mask = netmask;
+       m->rm_mklist = *mp;
+       *mp = m;
+       tt->rn_mklist = m;
+       return tt;
+}
+
+struct radix_node *
+rn_delete(v, netmask, head)
+       caddr_t v, netmask;
+       struct radix_node *head;
+{
+       register struct radix_node *t, *p, *x = head;
+       register struct radix_node *tt = rn_search(v, x);
+       int b, head_off = x->rn_off, vlen =  * (u_char *) v;
+       struct radix_mask *m, *saved_m, **mp;
+       struct radix_node *dupedkey, *saved_tt = tt;
+
+       if (tt == 0 ||
+           Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
+               return (0);
+       /*
+        * Delete our route from mask lists.
+        */
+       if (dupedkey = tt->rn_dupedkey) {
+               if (netmask) 
+                       netmask = rn_search(netmask, rn_maskhead)->rn_key;
+               while (tt->rn_mask != netmask)
+                       if ((tt = tt->rn_dupedkey) == 0)
+                               return (0);
+       }
+       if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
+               goto on1;
+       if (m->rm_mask != tt->rn_mask) {
+               printf("rn_delete: inconsistent annotation\n");
+               goto on1;
+       }
+       if (--m->rm_refs >= 0)
+               goto on1;
+       b = -1 - tt->rn_b;
+       t = saved_tt->rn_p;
+       if (b > t->rn_b)
+               goto on1; /* Wasn't lifted at all */
+       do {
+               x = t;
+               t = t->rn_p;
+       } while (b <= t->rn_b && x != head);
+       for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist)
+               if (m == saved_m) {
+                       *mp = m->rm_mklist;
+                       MKFree(m);
+                       break;
+               }
+       if (m == 0)
+               printf("rn_delete: couldn't find our annotation\n");
+on1:
+       /*
+        * Eliminate us from tree
+        */
+       if (tt->rn_flags & RNF_ROOT)
+               return (0);
+#ifdef RN_DEBUG
+       /* Get us out of the creation list */
+       for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
+       if (t) t->rn_ybro = tt->rn_ybro;
+#endif RN_DEBUG
+       t = tt->rn_p;
+       if (dupedkey) {
+               if (tt == saved_tt) {
+                       x = dupedkey; x->rn_p = t;
+                       if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x;
+#ifndef RN_DEBUG
+                       x++; t = tt + 1; *x = *t; p = t->rn_p;
+#else
+                       x++; b = x->rn_info; t = tt + 1; *x = *t; p = t->rn_p;
+                       x->rn_info = b;
+#endif
+                       if (p->rn_l == t) p->rn_l = x; else p->rn_r = x;
+                       x->rn_l->rn_p = x; x->rn_r->rn_p = x;
+               } else {
+                       for (p = saved_tt; p && p->rn_dupedkey != tt;)
+                               p = p->rn_dupedkey;
+                       if (p) p->rn_dupedkey = tt->rn_dupedkey;
+                       else printf("rn_delete: couldn't find us\n");
+               }
+               goto out;
+       }
+       if (t->rn_l == tt) x = t->rn_r; else x = t->rn_l;
+       p = t->rn_p;
+       if (p->rn_r == t) p->rn_r = x; else p->rn_l = x;
+       x->rn_p = p;
+       /*
+        * Demote routes attached to us.
+        */
+       if (t->rn_mklist) {
+               if (x->rn_b >= 0) {
+                       for (mp = &x->rn_mklist; m = *mp;)
+                               mp = &m->rm_mklist;
+                       *mp = t->rn_mklist;
+               } else {
+                       for (m = t->rn_mklist; m;) {
+                               struct radix_mask *mm = m->rm_mklist;
+                               if (m == x->rn_mklist && (--(m->rm_refs) < 0)) {
+                                       x->rn_mklist = 0;
+                                       MKFree(m);
+                               } else 
+                                       printf("%s %x at %x\n",
+                                           "rn_delete: Orphaned Mask", m, x);
+                               m = mm;
+                       }
+               }
+       }
+       /*
+        * We may be holding an active internal node in the tree.
+        */
+       x = tt + 1;
+       if (t != x) {
+#ifndef RN_DEBUG
+               *t = *x;
+#else
+               b = t->rn_info; *t = *x; t->rn_info = b;
+#endif
+               t->rn_l->rn_p = t; t->rn_r->rn_p = t;
+               p = x->rn_p;
+               if (p->rn_l == x) p->rn_l = t; else p->rn_r = t;
+       }
+out:
+       tt->rn_flags &= ~RNF_ACTIVE;
+       tt[1].rn_flags &= ~RNF_ACTIVE;
+       return (tt);
+}
+char rn_zeros[MAXKEYLEN], rn_ones[MAXKEYLEN];
+
+rn_inithead(head, off, af)
+struct radix_node_head **head;
+int off;
+{
+       register struct radix_node_head *rnh;
+       register struct radix_node *t, *tt, *ttt;
+       if (*head)
+               return (1);
+       R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh));
+       if (rnh == 0)
+               return (0);
+       Bzero(rnh, sizeof (*rnh));
+       *head = rnh;
+       t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
+       ttt = rnh->rnh_nodes + 2;
+       t->rn_r = ttt;
+       t->rn_p = t;
+       tt = t->rn_l;
+       tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
+       tt->rn_b = -1 - off;
+       *ttt = *tt;
+       ttt->rn_key = rn_ones;
+       rnh->rnh_af = af;
+       rnh->rnh_treetop = t;
+       if (radix_node_head == 0) {
+               caddr_t cp = rn_ones, cplim = rn_ones + MAXKEYLEN;
+               while (cp < cplim)
+                       *cp++ = -1;
+               if (rn_inithead(&radix_node_head, 0, 0) == 0) {
+                       Free(rnh);
+                       *head = 0;
+                       return (0);
+               }
+               mask_rnhead = radix_node_head;
+       }
+       rnh->rnh_next = radix_node_head->rnh_next;
+       if (radix_node_head != rnh)
+               radix_node_head->rnh_next = rnh;
+       return (1);
+}
diff --git a/usr/src/sys.386bsd/net/radix.h b/usr/src/sys.386bsd/net/radix.h
new file mode 100644 (file)
index 0000000..349e969
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1988, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)radix.h     7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Radix search tree node layout.
+ */
+
+struct radix_node {
+       struct  radix_mask *rn_mklist;  /* list of masks contained in subtree */
+       struct  radix_node *rn_p;       /* parent */
+       short   rn_b;                   /* bit offset; -1-index(netmask) */
+       char    rn_bmask;               /* node: mask for bit test*/
+       u_char  rn_flags;               /* enumerated next */
+#define RNF_NORMAL     1               /* leaf contains normal route */
+#define RNF_ROOT       2               /* leaf is root leaf for tree */
+#define RNF_ACTIVE     4               /* This node is alive (for rtfree) */
+       union {
+               struct {                        /* leaf only data: */
+                       caddr_t rn_Key; /* object of search */
+                       caddr_t rn_Mask;        /* netmask, if present */
+                       struct  radix_node *rn_Dupedkey;
+               } rn_leaf;
+               struct {                        /* node only data: */
+                       int     rn_Off;         /* where to start compare */
+                       struct  radix_node *rn_L;/* progeny */
+                       struct  radix_node *rn_R;/* progeny */
+               }rn_node;
+       }               rn_u;
+#ifdef RN_DEBUG
+       int rn_info;
+       struct radix_node *rn_twin;
+       struct radix_node *rn_ybro;
+#endif
+};
+
+#define MAXKEYLEN 32
+
+#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
+#define rn_key rn_u.rn_leaf.rn_Key
+#define rn_mask rn_u.rn_leaf.rn_Mask
+#define rn_off rn_u.rn_node.rn_Off
+#define rn_l rn_u.rn_node.rn_L
+#define rn_r rn_u.rn_node.rn_R
+
+/*
+ * Annotations to tree concerning potential routes applying to subtrees.
+ */
+
+extern struct radix_mask {
+       short   rm_b;                   /* bit offset; -1-index(netmask) */
+       char    rm_unused;              /* cf. rn_bmask */
+       u_char  rm_flags;               /* cf. rn_flags */
+       struct  radix_mask *rm_mklist;  /* more masks to try */
+       caddr_t rm_mask;                /* the mask */
+       int     rm_refs;                /* # of references to this struct */
+} *rn_mkfreelist;
+
+#define MKGet(m) {\
+       if (rn_mkfreelist) {\
+               m = rn_mkfreelist; \
+               rn_mkfreelist = (m)->rm_mklist; \
+       } else \
+               R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\
+
+#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
+
+extern struct radix_node_head {
+       struct  radix_node_head *rnh_next;
+       struct  radix_node *rnh_treetop;
+       int     rnh_af;
+       struct  radix_node rnh_nodes[3];
+} *radix_node_head;
+
+
+#ifndef KERNEL
+#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n))
+#define Bzero(p, n) bzero((char *)(p), (int)(n));
+#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
+#define Free(p) free((char *)p);
+#else
+#define Bcmp(a, b, n) bcmp(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
+#define Bcopy(a, b, n) bcopy(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
+#define Bzero(p, n) bzero((caddr_t)(p), (unsigned)(n));
+#define R_Malloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_DONTWAIT))
+#define Free(p) free((caddr_t)p, M_RTABLE);
+#endif /*KERNEL*/
diff --git a/usr/src/sys.386bsd/net/raw_cb.c b/usr/src/sys.386bsd/net/raw_cb.c
new file mode 100644 (file)
index 0000000..87f6ca4
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1980, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)raw_cb.c    7.11 (Berkeley) 6/28/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "domain.h"
+#include "protosw.h"
+#include "errno.h"
+
+#include "if.h"
+#include "route.h"
+#include "raw_cb.h"
+#include "../netinet/in.h"
+
+#include "machine/mtpr.h"
+
+/*
+ * Routines to manage the raw protocol control blocks. 
+ *
+ * TODO:
+ *     hash lookups by protocol family/protocol + address family
+ *     take care of unique address problems per AF?
+ *     redo address binding to allow wildcards
+ */
+
+u_long raw_sendspace = RAWSNDQ;
+u_long raw_recvspace = RAWRCVQ;
+
+/*
+ * Allocate a control block and a nominal amount
+ * of buffer space for the socket.
+ */
+raw_attach(so, proto)
+       register struct socket *so;
+       int proto;
+{
+       register struct rawcb *rp = sotorawcb(so);
+       int error;
+
+       /*
+        * It is assumed that raw_attach is called
+        * after space has been allocated for the
+        * rawcb.
+        */
+       if (rp == 0)
+               return (ENOBUFS);
+       if (error = soreserve(so, raw_sendspace, raw_recvspace))
+               return (error);
+       rp->rcb_socket = so;
+       rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family;
+       rp->rcb_proto.sp_protocol = proto;
+       insque(rp, &rawcb);
+       return (0);
+}
+
+/*
+ * Detach the raw connection block and discard
+ * socket resources.
+ */
+raw_detach(rp)
+       register struct rawcb *rp;
+{
+       struct socket *so = rp->rcb_socket;
+
+       so->so_pcb = 0;
+       sofree(so);
+       remque(rp);
+#ifdef notdef
+       if (rp->rcb_laddr)
+               m_freem(dtom(rp->rcb_laddr));
+       rp->rcb_laddr = 0;
+#endif
+       free((caddr_t)(rp), M_PCB);
+}
+
+/*
+ * Disconnect and possibly release resources.
+ */
+raw_disconnect(rp)
+       struct rawcb *rp;
+{
+
+#ifdef notdef
+       if (rp->rcb_faddr)
+               m_freem(dtom(rp->rcb_faddr));
+       rp->rcb_faddr = 0;
+#endif
+       if (rp->rcb_socket->so_state & SS_NOFDREF)
+               raw_detach(rp);
+}
+
+#ifdef notdef
+raw_bind(so, nam)
+       register struct socket *so;
+       struct mbuf *nam;
+{
+       struct sockaddr *addr = mtod(nam, struct sockaddr *);
+       register struct rawcb *rp;
+
+       if (ifnet == 0)
+               return (EADDRNOTAVAIL);
+       rp = sotorawcb(so);
+       nam = m_copym(nam, 0, M_COPYALL, M_WAITOK);
+       rp->rcb_laddr = mtod(nam, struct sockaddr *);
+       return (0);
+}
+#endif
diff --git a/usr/src/sys.386bsd/net/raw_cb.h b/usr/src/sys.386bsd/net/raw_cb.h
new file mode 100644 (file)
index 0000000..aab20b5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1980, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)raw_cb.h    7.6 (Berkeley) 6/28/90
+ */
+
+/*
+ * Raw protocol interface control block.  Used
+ * to tie a socket to the generic raw interface.
+ */
+struct rawcb {
+       struct  rawcb *rcb_next;        /* doubly linked list */
+       struct  rawcb *rcb_prev;
+       struct  socket *rcb_socket;     /* back pointer to socket */
+       struct  sockaddr *rcb_faddr;    /* destination address */
+       struct  sockaddr *rcb_laddr;    /* socket's address */
+       struct  sockproto rcb_proto;    /* protocol family, protocol */
+};
+
+#define        sotorawcb(so)           ((struct rawcb *)(so)->so_pcb)
+
+/*
+ * Nominal space allocated to a raw socket.
+ */
+#define        RAWSNDQ         8192
+#define        RAWRCVQ         8192
+
+#ifdef KERNEL
+struct rawcb rawcb;                    /* head of list */
+#endif
diff --git a/usr/src/sys.386bsd/net/raw_usrreq.c b/usr/src/sys.386bsd/net/raw_usrreq.c
new file mode 100644 (file)
index 0000000..511cff3
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 1980, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)raw_usrreq.c        7.9 (Berkeley) 6/28/90
+ */
+
+#include "param.h"
+#include "mbuf.h"
+#include "domain.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "errno.h"
+
+#include "if.h"
+#include "route.h"
+#include "netisr.h"
+#include "raw_cb.h"
+
+#include "machine/mtpr.h"
+
+/*
+ * Initialize raw connection block q.
+ */
+raw_init()
+{
+
+       rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
+       rawintrq.ifq_maxlen = IFQ_MAXLEN;
+}
+
+
+/*
+ * Raw protocol input routine.  Find the socket
+ * associated with the packet(s) and move them over.  If
+ * nothing exists for this packet, drop it.
+ */
+/*
+ * Raw protocol interface.
+ */
+raw_input(m0, proto, src, dst)
+       struct mbuf *m0;
+       register struct sockproto *proto;
+       struct sockaddr *src, *dst;
+{
+       register struct rawcb *rp;
+       register struct mbuf *m = m0;
+       register int sockets = 0;
+       struct socket *last;
+
+       last = 0;
+       for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
+               if (rp->rcb_proto.sp_family != proto->sp_family)
+                       continue;
+               if (rp->rcb_proto.sp_protocol  &&
+                   rp->rcb_proto.sp_protocol != proto->sp_protocol)
+                       continue;
+               /*
+                * We assume the lower level routines have
+                * placed the address in a canonical format
+                * suitable for a structure comparison.
+                *
+                * Note that if the lengths are not the same
+                * the comparison will fail at the first byte.
+                */
+#define        equal(a1, a2) \
+  (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0)
+               if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst))
+                       continue;
+               if (rp->rcb_faddr && !equal(rp->rcb_faddr, src))
+                       continue;
+               if (last) {
+                       struct mbuf *n;
+                       if (n = m_copy(m, 0, (int)M_COPYALL)) {
+                               if (sbappendaddr(&last->so_rcv, src,
+                                   n, (struct mbuf *)0) == 0)
+                                       /* should notify about lost packet */
+                                       m_freem(n);
+                               else {
+                                       sorwakeup(last);
+                                       sockets++;
+                               }
+                       }
+               }
+               last = rp->rcb_socket;
+       }
+       if (last) {
+               if (sbappendaddr(&last->so_rcv, src,
+                   m, (struct mbuf *)0) == 0)
+                       m_freem(m);
+               else {
+                       sorwakeup(last);
+                       sockets++;
+               }
+       } else
+               m_freem(m);
+       return (sockets);
+}
+
+/*ARGSUSED*/
+raw_ctlinput(cmd, arg)
+       int cmd;
+       struct sockaddr *arg;
+{
+
+       if (cmd < 0 || cmd > PRC_NCMDS)
+               return;
+       /* INCOMPLETE */
+}
+
+/*ARGSUSED*/
+raw_usrreq(so, req, m, nam, control)
+       struct socket *so;
+       int req;
+       struct mbuf *m, *nam, *control;
+{
+       register struct rawcb *rp = sotorawcb(so);
+       register int error = 0;
+       int len;
+
+       if (req == PRU_CONTROL)
+               return (EOPNOTSUPP);
+       if (control && control->m_len) {
+               error = EOPNOTSUPP;
+               goto release;
+       }
+       if (rp == 0) {
+               error = EINVAL;
+               goto release;
+       }
+       switch (req) {
+
+       /*
+        * Allocate a raw control block and fill in the
+        * necessary info to allow packets to be routed to
+        * the appropriate raw interface routine.
+        */
+       case PRU_ATTACH:
+               if ((so->so_state & SS_PRIV) == 0) {
+                       error = EACCES;
+                       break;
+               }
+               error = raw_attach(so, (int)nam);
+               break;
+
+       /*
+        * Destroy state just before socket deallocation.
+        * Flush data or not depending on the options.
+        */
+       case PRU_DETACH:
+               if (rp == 0) {
+                       error = ENOTCONN;
+                       break;
+               }
+               raw_detach(rp);
+               break;
+
+#ifdef notdef
+       /*
+        * If a socket isn't bound to a single address,
+        * the raw input routine will hand it anything
+        * within that protocol family (assuming there's
+        * nothing else around it should go to). 
+        */
+       case PRU_CONNECT:
+               if (rp->rcb_faddr) {
+                       error = EISCONN;
+                       break;
+               }
+               nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
+               rp->rcb_faddr = mtod(nam, struct sockaddr *);
+               soisconnected(so);
+               break;
+
+       case PRU_BIND:
+               if (rp->rcb_laddr) {
+                       error = EINVAL;                 /* XXX */
+                       break;
+               }
+               error = raw_bind(so, nam);
+               break;
+#endif
+
+       case PRU_CONNECT2:
+               error = EOPNOTSUPP;
+               goto release;
+
+       case PRU_DISCONNECT:
+               if (rp->rcb_faddr == 0) {
+                       error = ENOTCONN;
+                       break;
+               }
+               raw_disconnect(rp);
+               soisdisconnected(so);
+               break;
+
+       /*
+        * Mark the connection as being incapable of further input.
+        */
+       case PRU_SHUTDOWN:
+               socantsendmore(so);
+               break;
+
+       /*
+        * Ship a packet out.  The appropriate raw output
+        * routine handles any massaging necessary.
+        */
+       case PRU_SEND:
+               if (nam) {
+                       if (rp->rcb_faddr) {
+                               error = EISCONN;
+                               break;
+                       }
+                       rp->rcb_faddr = mtod(nam, struct sockaddr *);
+               } else if (rp->rcb_faddr == 0) {
+                       error = ENOTCONN;
+                       break;
+               }
+               error = (*so->so_proto->pr_output)(m, so);
+               m = NULL;
+               if (nam)
+                       rp->rcb_faddr = 0;
+               break;
+
+       case PRU_ABORT:
+               raw_disconnect(rp);
+               sofree(so);
+               soisdisconnected(so);
+               break;
+
+       case PRU_SENSE:
+               /*
+                * stat: don't bother with a blocksize.
+                */
+               return (0);
+
+       /*
+        * Not supported.
+        */
+       case PRU_RCVOOB:
+       case PRU_RCVD:
+               return(EOPNOTSUPP);
+
+       case PRU_LISTEN:
+       case PRU_ACCEPT:
+       case PRU_SENDOOB:
+               error = EOPNOTSUPP;
+               break;
+
+       case PRU_SOCKADDR:
+               if (rp->rcb_laddr == 0) {
+                       error = EINVAL;
+                       break;
+               }
+               len = rp->rcb_laddr->sa_len;
+               bcopy((caddr_t)rp->rcb_laddr, mtod(nam, caddr_t), (unsigned)len);
+               nam->m_len = len;
+               break;
+
+       case PRU_PEERADDR:
+               if (rp->rcb_faddr == 0) {
+                       error = ENOTCONN;
+                       break;
+               }
+               len = rp->rcb_faddr->sa_len;
+               bcopy((caddr_t)rp->rcb_faddr, mtod(nam, caddr_t), (unsigned)len);
+               nam->m_len = len;
+               break;
+
+       default:
+               panic("raw_usrreq");
+       }
+release:
+       if (m != NULL)
+               m_freem(m);
+       return (error);
+}
+
+rawintr() {} /* XXX - referenced by locore.  will soon go away */
diff --git a/usr/src/sys.386bsd/net/route.c b/usr/src/sys.386bsd/net/route.c
new file mode 100644 (file)
index 0000000..2d69294
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 1980, 1986, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)route.c     7.22 (Berkeley) 6/27/91
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "domain.h"
+#include "protosw.h"
+#include "ioctl.h"
+
+#include "if.h"
+#include "af.h"
+#include "route.h"
+#include "raw_cb.h"
+
+#include "../netinet/in.h"
+#include "../netinet/in_var.h"
+
+#ifdef NS
+#include "../netns/ns.h"
+#endif
+#include "machine/mtpr.h"
+#include "netisr.h"
+
+#define        SA(p) ((struct sockaddr *)(p))
+
+int    rttrash;                /* routes not in table but not freed */
+struct sockaddr wildcard;      /* zero valued cookie for wildcard searches */
+int    rthashsize = RTHASHSIZ; /* for netstat, etc. */
+
+static int rtinits_done = 0;
+struct radix_node_head *ns_rnhead, *in_rnhead;
+struct radix_node *rn_match(), *rn_delete(), *rn_addroute();
+
+rtinitheads()
+{
+       if (rtinits_done == 0 &&
+#ifdef NS
+           rn_inithead(&ns_rnhead, 16, AF_NS) &&
+#endif
+           rn_inithead(&in_rnhead, 32, AF_INET))
+               rtinits_done = 1;
+}
+
+/*
+ * Packet routing routines.
+ */
+rtalloc(ro)
+       register struct route *ro;
+{
+       if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
+               return;                          /* XXX */
+       ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
+}
+
+struct rtentry *
+rtalloc1(dst, report)
+       register struct sockaddr *dst;
+       int  report;
+{
+       register struct radix_node_head *rnh;
+       register struct rtentry *rt;
+       register struct radix_node *rn;
+       struct rtentry *newrt = 0;
+       int  s = splnet(), err = 0, msgtype = RTM_MISS;
+
+       for (rnh = radix_node_head; rnh && (dst->sa_family != rnh->rnh_af); )
+               rnh = rnh->rnh_next;
+       if (rnh && rnh->rnh_treetop &&
+           (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) &&
+           ((rn->rn_flags & RNF_ROOT) == 0)) {
+               newrt = rt = (struct rtentry *)rn;
+               if (report && (rt->rt_flags & RTF_CLONING)) {
+                       if ((err = rtrequest(RTM_RESOLVE, dst, SA(0),
+                                             SA(0), 0, &newrt)) ||
+                           ((rt->rt_flags & RTF_XRESOLVE)
+                             && (msgtype = RTM_RESOLVE))) /* intended! */
+                           goto miss;
+               } else
+                       rt->rt_refcnt++;
+       } else {
+               rtstat.rts_unreach++;
+       miss:   if (report)
+                       rt_missmsg(msgtype, dst, SA(0), SA(0), SA(0), 0, err);
+       }
+       splx(s);
+       return (newrt);
+}
+
+rtfree(rt)
+       register struct rtentry *rt;
+{
+       register struct ifaddr *ifa;
+       if (rt == 0)
+               panic("rtfree");
+       rt->rt_refcnt--;
+       if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
+               rttrash--;
+               if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+                       panic ("rtfree 2");
+               free((caddr_t)rt, M_RTABLE);
+       }
+}
+
+/*
+ * Force a routing table entry to the specified
+ * destination to go through the given gateway.
+ * Normally called as a result of a routing redirect
+ * message from the network layer.
+ *
+ * N.B.: must be called at splnet
+ *
+ */
+rtredirect(dst, gateway, netmask, flags, src, rtp)
+       struct sockaddr *dst, *gateway, *netmask, *src;
+       int flags;
+       struct rtentry **rtp;
+{
+       register struct rtentry *rt;
+       int error = 0;
+       short *stat = 0;
+
+       /* verify the gateway is directly reachable */
+       if (ifa_ifwithnet(gateway) == 0) {
+               error = ENETUNREACH;
+               goto done;
+       }
+       rt = rtalloc1(dst, 0);
+       /*
+        * If the redirect isn't from our current router for this dst,
+        * it's either old or wrong.  If it redirects us to ourselves,
+        * we have a routing loop, perhaps as a result of an interface
+        * going down recently.
+        */
+#define        equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
+       if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway))
+               error = EINVAL;
+       else if (ifa_ifwithaddr(gateway))
+               error = EHOSTUNREACH;
+       if (error)
+               goto done;
+       /*
+        * Create a new entry if we just got back a wildcard entry
+        * or the the lookup failed.  This is necessary for hosts
+        * which use routing redirects generated by smart gateways
+        * to dynamically build the routing tables.
+        */
+       if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
+               goto create;
+       /*
+        * Don't listen to the redirect if it's
+        * for a route to an interface. 
+        */
+       if (rt->rt_flags & RTF_GATEWAY) {
+               if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
+                       /*
+                        * Changing from route to net => route to host.
+                        * Create new route, rather than smashing route to net.
+                        */
+               create:
+                       flags |=  RTF_GATEWAY | RTF_DYNAMIC;
+                       error = rtrequest((int)RTM_ADD, dst, gateway,
+                                   SA(0), flags,
+                                   (struct rtentry **)0);
+                       stat = &rtstat.rts_dynamic;
+               } else {
+                       /*
+                        * Smash the current notion of the gateway to
+                        * this destination.  Should check about netmask!!!
+                        */
+                       if (gateway->sa_len <= rt->rt_gateway->sa_len) {
+                               Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
+                               rt->rt_flags |= RTF_MODIFIED;
+                               flags |= RTF_MODIFIED;
+                               stat = &rtstat.rts_newgateway;
+                       } else
+                               error = ENOSPC;
+               }
+       } else
+               error = EHOSTUNREACH;
+done:
+       if (rt) {
+               if (rtp && !error)
+                       *rtp = rt;
+               else
+                       rtfree(rt);
+       }
+       if (error)
+               rtstat.rts_badredirect++;
+       else
+               (stat && (*stat)++);
+       rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src, flags, error);
+}
+
+/*
+* Routing table ioctl interface.
+*/
+rtioctl(req, data, p)
+       int req;
+       caddr_t data;
+       struct proc *p;
+{
+#ifndef COMPAT_43
+       return (EOPNOTSUPP);
+#else
+       register struct ortentry *entry = (struct ortentry *)data;
+       int error;
+       struct sockaddr *netmask = 0;
+
+       if (req == SIOCADDRT)
+               req = RTM_ADD;
+       else if (req == SIOCDELRT)
+               req = RTM_DELETE;
+       else
+               return (EINVAL);
+
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+#if BYTE_ORDER != BIG_ENDIAN
+       if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) {
+               entry->rt_dst.sa_family = entry->rt_dst.sa_len;
+               entry->rt_dst.sa_len = 16;
+       }
+       if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) {
+               entry->rt_gateway.sa_family = entry->rt_gateway.sa_len;
+               entry->rt_gateway.sa_len = 16;
+       }
+#else
+       if (entry->rt_dst.sa_len == 0)
+               entry->rt_dst.sa_len = 16;
+       if (entry->rt_gateway.sa_len == 0)
+               entry->rt_gateway.sa_len = 16;
+#endif
+       if ((entry->rt_flags & RTF_HOST) == 0)
+               switch (entry->rt_dst.sa_family) {
+#ifdef INET
+               case AF_INET:
+                       {
+                               extern struct sockaddr_in icmpmask;
+                               struct sockaddr_in *dst_in = 
+                                       (struct sockaddr_in *)&entry->rt_dst;
+
+                               in_sockmaskof(dst_in->sin_addr, &icmpmask);
+                               netmask = (struct sockaddr *)&icmpmask;
+                       }
+                       break;
+#endif
+#ifdef NS
+               case AF_NS:
+                       {
+                               extern struct sockaddr_ns ns_netmask;
+                               netmask = (struct sockaddr *)&ns_netmask;
+                       }
+#endif
+               }
+       error =  rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask,
+                               entry->rt_flags, (struct rtentry **)0);
+       rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL),
+                  &(entry->rt_dst), &(entry->rt_gateway),
+                  netmask, SA(0), entry->rt_flags, error);
+       return (error);
+#endif
+}
+
+struct ifaddr *
+ifa_ifwithroute(flags, dst, gateway)
+int    flags;
+struct sockaddr        *dst, *gateway;
+{
+       register struct ifaddr *ifa;
+       if ((flags & RTF_GATEWAY) == 0) {
+               /*
+                * If we are adding a route to an interface,
+                * and the interface is a pt to pt link
+                * we should search for the destination
+                * as our clue to the interface.  Otherwise
+                * we can use the local address.
+                */
+               ifa = 0;
+               if (flags & RTF_HOST) 
+                       ifa = ifa_ifwithdstaddr(dst);
+               if (ifa == 0)
+                       ifa = ifa_ifwithaddr(gateway);
+       } else {
+               /*
+                * If we are adding a route to a remote net
+                * or host, the gateway may still be on the
+                * other end of a pt to pt link.
+                */
+               ifa = ifa_ifwithdstaddr(gateway);
+       }
+       if (ifa == 0)
+               ifa = ifa_ifwithnet(gateway);
+       if (ifa == 0) {
+               struct rtentry *rt = rtalloc1(dst, 0);
+               if (rt == 0)
+                       return (0);
+               rt->rt_refcnt--;
+               if ((ifa = rt->rt_ifa) == 0)
+                       return (0);
+       }
+       if (ifa->ifa_addr->sa_family != dst->sa_family) {
+               struct ifaddr *oifa = ifa, *ifaof_ifpforaddr();
+               ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
+               if (ifa == 0)
+                       ifa = oifa;
+       }
+       return (ifa);
+}
+
+#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
+       int req, flags;
+       struct sockaddr *dst, *gateway, *netmask;
+       struct rtentry **ret_nrt;
+{
+       int s = splnet(), len, error = 0;
+       register struct rtentry *rt;
+       register struct radix_node *rn;
+       register struct radix_node_head *rnh;
+       struct ifaddr *ifa, *ifa_ifwithdstaddr();
+       struct sockaddr *ndst;
+       u_char af = dst->sa_family;
+#define senderr(x) { error = x ; goto bad; }
+
+       if (rtinits_done == 0)
+               rtinitheads();
+       for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
+               rnh = rnh->rnh_next;
+       if (rnh == 0)
+               senderr(ESRCH);
+       if (flags & RTF_HOST)
+               netmask = 0;
+       switch (req) {
+       case RTM_DELETE:
+               if (ret_nrt && (rt = *ret_nrt)) {
+                       RTFREE(rt);
+                       *ret_nrt = 0;
+               }
+               if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask, 
+                                       rnh->rnh_treetop)) == 0)
+                       senderr(ESRCH);
+               if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+                       panic ("rtrequest delete");
+               rt = (struct rtentry *)rn;
+               rt->rt_flags &= ~RTF_UP;
+               if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
+                       ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
+               rttrash++;
+               if (rt->rt_refcnt <= 0)
+                       rtfree(rt);
+               break;
+
+       case RTM_RESOLVE:
+               if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
+                       senderr(EINVAL);
+               ifa = rt->rt_ifa;
+               flags = rt->rt_flags & ~RTF_CLONING;
+               gateway = rt->rt_gateway;
+               if ((netmask = rt->rt_genmask) == 0)
+                       flags |= RTF_HOST;
+               goto makeroute;
+
+       case RTM_ADD:
+               if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
+                       senderr(ENETUNREACH);
+       makeroute:
+               len = sizeof (*rt) + ROUNDUP(gateway->sa_len)
+                   + ROUNDUP(dst->sa_len);
+               R_Malloc(rt, struct rtentry *, len);
+               if (rt == 0)
+                       senderr(ENOBUFS);
+               Bzero(rt, len);
+               ndst = (struct sockaddr *)(rt + 1);
+               if (netmask) {
+                       rt_maskedcopy(dst, ndst, netmask);
+               } else
+                       Bcopy(dst, ndst, dst->sa_len);
+               rn = rn_addroute((caddr_t)ndst, (caddr_t)netmask,
+                                       rnh->rnh_treetop, rt->rt_nodes);
+               if (rn == 0) {
+                       free((caddr_t)rt, M_RTABLE);
+                       senderr(EEXIST);
+               }
+               rt->rt_ifa = ifa;
+               rt->rt_ifp = ifa->ifa_ifp;
+               rt->rt_flags = RTF_UP | flags;
+               rt->rt_gateway = (struct sockaddr *)
+                                       (rn->rn_key + ROUNDUP(dst->sa_len));
+               Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
+               if (req == RTM_RESOLVE)
+                       rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
+               if (ifa->ifa_rtrequest)
+                       ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
+               if (ret_nrt) {
+                       *ret_nrt = rt;
+                       rt->rt_refcnt++;
+               }
+               break;
+       }
+bad:
+       splx(s);
+       return (error);
+}
+
+rt_maskedcopy(src, dst, netmask)
+struct sockaddr *src, *dst, *netmask;
+{
+       register u_char *cp1 = (u_char *)src;
+       register u_char *cp2 = (u_char *)dst;
+       register u_char *cp3 = (u_char *)netmask;
+       u_char *cplim = cp2 + *cp3;
+       u_char *cplim2 = cp2 + *cp1;
+
+       *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
+       cp3 += 2;
+       if (cplim > cplim2)
+               cplim = cplim2;
+       while (cp2 < cplim)
+               *cp2++ = *cp1++ & *cp3++;
+       if (cp2 < cplim2)
+               bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
+}
+/*
+ * Set up a routing table entry, normally
+ * for an interface.
+ */
+rtinit(ifa, cmd, flags)
+       register struct ifaddr *ifa;
+       int cmd, flags;
+{
+       register struct rtentry *rt;
+       register struct sockaddr *dst;
+       register struct sockaddr *deldst;
+       struct mbuf *m = 0;
+       int error;
+
+       dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
+       if (ifa->ifa_flags & IFA_ROUTE) {
+               if ((rt = ifa->ifa_rt) && (rt->rt_flags & RTF_UP) == 0) {
+                       RTFREE(rt);
+                       ifa->ifa_rt = 0;
+               }
+       }
+       if (cmd == RTM_DELETE) {
+               if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
+                       m = m_get(M_WAIT, MT_SONAME);
+                       deldst = mtod(m, struct sockaddr *);
+                       rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
+                       dst = deldst;
+               }
+               if (rt = rtalloc1(dst, 0)) {
+                       rt->rt_refcnt--;
+                       if (rt->rt_ifa != ifa) {
+                               if (m)
+                                       (void) m_free(m);
+                               return (flags & RTF_HOST ? EHOSTUNREACH
+                                                       : ENETUNREACH);
+                       }
+               }
+       }
+       error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
+                       flags | ifa->ifa_flags, &ifa->ifa_rt);
+       if (m)
+               (void) m_free(m);
+       if (cmd == RTM_ADD && error == 0 && (rt = ifa->ifa_rt)
+                                               && rt->rt_ifa != ifa) {
+               rt->rt_ifa = ifa;
+               rt->rt_ifp = ifa->ifa_ifp;
+       }
+       return (error);
+}
diff --git a/usr/src/sys.386bsd/net/route.h b/usr/src/sys.386bsd/net/route.h
new file mode 100644 (file)
index 0000000..4db57cf
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 1980, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)route.h     7.13 (Berkeley) 4/25/91
+ */
+
+/*
+ * Kernel resident routing tables.
+ * 
+ * The routing tables are initialized when interface addresses
+ * are set by making entries for all directly connected interfaces.
+ */
+
+/*
+ * A route consists of a destination address and a reference
+ * to a routing entry.  These are often held by protocols
+ * in their control blocks, e.g. inpcb.
+ */
+struct route {
+       struct  rtentry *ro_rt;
+       struct  sockaddr ro_dst;
+};
+
+/*
+ * These numbers are used by reliable protocols for determining
+ * retransmission behavior and are included in the routing structure.
+ */
+struct rt_metrics {
+       u_long  rmx_locks;      /* Kernel must leave these values alone */
+       u_long  rmx_mtu;        /* MTU for this path */
+       u_long  rmx_hopcount;   /* max hops expected */
+       u_long  rmx_expire;     /* lifetime for route, e.g. redirect */
+       u_long  rmx_recvpipe;   /* inbound delay-bandwith product */
+       u_long  rmx_sendpipe;   /* outbound delay-bandwith product */
+       u_long  rmx_ssthresh;   /* outbound gateway buffer limit */
+       u_long  rmx_rtt;        /* estimated round trip time */
+       u_long  rmx_rttvar;     /* estimated rtt variance */
+};
+
+/*
+ * rmx_rtt and rmx_rttvar are stored as microseconds;
+ * RTTTOPRHZ(rtt) converts to a value suitable for use
+ * by a protocol slowtimo counter.
+ */
+#define        RTM_RTTUNIT     1000000 /* units for rtt, rttvar, as units per sec */
+#define        RTTTOPRHZ(r)    ((r) / (RTM_RTTUNIT / PR_SLOWHZ))
+
+/*
+ * We distinguish between routes to hosts and routes to networks,
+ * preferring the former if available.  For each route we infer
+ * the interface to use from the gateway address supplied when
+ * the route was entered.  Routes that forward packets through
+ * gateways are marked so that the output routines know to address the
+ * gateway rather than the ultimate destination.
+ */
+#ifndef RNF_NORMAL
+#include "radix.h"
+#endif
+struct rtentry {
+       struct  radix_node rt_nodes[2]; /* tree glue, and other values */
+#define        rt_key(r)       ((struct sockaddr *)((r)->rt_nodes->rn_key))
+#define        rt_mask(r)      ((struct sockaddr *)((r)->rt_nodes->rn_mask))
+       struct  sockaddr *rt_gateway;   /* value */
+       short   rt_flags;               /* up/down?, host/net */
+       short   rt_refcnt;              /* # held references */
+       u_long  rt_use;                 /* raw # packets forwarded */
+       struct  ifnet *rt_ifp;          /* the answer: interface to use */
+       struct  ifaddr *rt_ifa;         /* the answer: interface to use */
+       struct  sockaddr *rt_genmask;   /* for generation of cloned routes */
+       caddr_t rt_llinfo;              /* pointer to link level info cache */
+       struct  rt_metrics rt_rmx;      /* metrics used by rx'ing protocols */
+       short   rt_idle;                /* easy to tell llayer still live */
+};
+
+/*
+ * Following structure necessary for 4.3 compatibility;
+ * We should eventually move it to a compat file.
+ */
+struct ortentry {
+       u_long  rt_hash;                /* to speed lookups */
+       struct  sockaddr rt_dst;        /* key */
+       struct  sockaddr rt_gateway;    /* value */
+       short   rt_flags;               /* up/down?, host/net */
+       short   rt_refcnt;              /* # held references */
+       u_long  rt_use;                 /* raw # packets forwarded */
+       struct  ifnet *rt_ifp;          /* the answer: interface to use */
+};
+
+#define        RTF_UP          0x1             /* route useable */
+#define        RTF_GATEWAY     0x2             /* destination is a gateway */
+#define        RTF_HOST        0x4             /* host entry (net otherwise) */
+#define        RTF_REJECT      0x8             /* host or net unreachable */
+#define        RTF_DYNAMIC     0x10            /* created dynamically (by redirect) */
+#define        RTF_MODIFIED    0x20            /* modified dynamically (by redirect) */
+#define RTF_DONE       0x40            /* message confirmed */
+#define RTF_MASK       0x80            /* subnet mask present */
+#define RTF_CLONING    0x100           /* generate new routes on use */
+#define RTF_XRESOLVE   0x200           /* external daemon resolves name */
+#define RTF_LLINFO     0x400           /* generated by ARP or ESIS */
+#define RTF_PROTO2     0x4000          /* protocol specific routing flag */
+#define RTF_PROTO1     0x8000          /* protocol specific routing flag */
+
+
+/*
+ * Routing statistics.
+ */
+struct rtstat {
+       short   rts_badredirect;        /* bogus redirect calls */
+       short   rts_dynamic;            /* routes created by redirects */
+       short   rts_newgateway;         /* routes modified by redirects */
+       short   rts_unreach;            /* lookups which failed */
+       short   rts_wildcard;           /* lookups satisfied by a wildcard */
+};
+/*
+ * Structures for routing messages.
+ */
+struct rt_msghdr {
+       u_short rtm_msglen;     /* to skip over non-understood messages */
+       u_char  rtm_version;    /* future binary compatability */
+       u_char  rtm_type;       /* message type */
+       u_short rtm_index;      /* index for associated ifp */
+       pid_t   rtm_pid;        /* identify sender */
+       int     rtm_addrs;      /* bitmask identifying sockaddrs in msg */
+       int     rtm_seq;        /* for sender to identify action */
+       int     rtm_errno;      /* why failed */
+       int     rtm_flags;      /* flags, incl. kern & message, e.g. DONE */
+       int     rtm_use;        /* from rtentry */
+       u_long  rtm_inits;      /* which metrics we are initializing */
+       struct  rt_metrics rtm_rmx; /* metrics themselves */
+};
+
+struct route_cb {
+       int     ip_count;
+       int     ns_count;
+       int     iso_count;
+       int     any_count;
+};
+#define RTM_VERSION    2       /* Up the ante and ignore older versions */
+
+#define RTM_ADD                0x1     /* Add Route */
+#define RTM_DELETE     0x2     /* Delete Route */
+#define RTM_CHANGE     0x3     /* Change Metrics or flags */
+#define RTM_GET                0x4     /* Report Metrics */
+#define RTM_LOSING     0x5     /* Kernel Suspects Partitioning */
+#define RTM_REDIRECT   0x6     /* Told to use different route */
+#define RTM_MISS       0x7     /* Lookup failed on this address */
+#define RTM_LOCK       0x8     /* fix specified metrics */
+#define RTM_OLDADD     0x9     /* caused by SIOCADDRT */
+#define RTM_OLDDEL     0xa     /* caused by SIOCDELRT */
+#define RTM_RESOLVE    0xb     /* req to resolve dst to LL addr */
+
+#define RTV_MTU                0x1     /* init or lock _mtu */
+#define RTV_HOPCOUNT   0x2     /* init or lock _hopcount */
+#define RTV_EXPIRE     0x4     /* init or lock _hopcount */
+#define RTV_RPIPE      0x8     /* init or lock _recvpipe */
+#define RTV_SPIPE      0x10    /* init or lock _sendpipe */
+#define RTV_SSTHRESH   0x20    /* init or lock _ssthresh */
+#define RTV_RTT                0x40    /* init or lock _rtt */
+#define RTV_RTTVAR     0x80    /* init or lock _rttvar */
+
+#define RTA_DST                0x1     /* destination sockaddr present */
+#define RTA_GATEWAY    0x2     /* gateway sockaddr present */
+#define RTA_NETMASK    0x4     /* netmask sockaddr present */
+#define RTA_GENMASK    0x8     /* cloning mask sockaddr present */
+#define RTA_IFP                0x10    /* interface name sockaddr present */
+#define RTA_IFA                0x20    /* interface addr sockaddr present */
+#define RTA_AUTHOR     0x40    /* sockaddr for author of redirect */
+
+#ifdef KERNEL
+struct route_cb route_cb;
+#endif
+
+#ifdef KERNEL
+#define        RTFREE(rt) \
+       if ((rt)->rt_refcnt <= 1) \
+               rtfree(rt); \
+       else \
+               (rt)->rt_refcnt--;
+
+#ifdef GATEWAY
+#define        RTHASHSIZ       64
+#else
+#define        RTHASHSIZ       8
+#endif
+#if    (RTHASHSIZ & (RTHASHSIZ - 1)) == 0
+#define RTHASHMOD(h)   ((h) & (RTHASHSIZ - 1))
+#else
+#define RTHASHMOD(h)   ((h) % RTHASHSIZ)
+#endif
+struct mbuf *rthost[RTHASHSIZ];
+struct mbuf *rtnet[RTHASHSIZ];
+struct rtstat  rtstat;
+struct rtentry *rtalloc1();
+#endif
diff --git a/usr/src/sys.386bsd/net/rtsock.c b/usr/src/sys.386bsd/net/rtsock.c
new file mode 100644 (file)
index 0000000..a64719b
--- /dev/null
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 1988, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)rtsock.c    7.18 (Berkeley) 6/27/91
+ */
+
+#include "param.h"
+#include "mbuf.h"
+#include "proc.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "domain.h"
+#include "protosw.h"
+
+#include "af.h"
+#include "if.h"
+#include "route.h"
+#include "raw_cb.h"
+
+#include "machine/mtpr.h"
+
+struct sockaddr route_dst = { 2, PF_ROUTE, };
+struct sockaddr route_src = { 2, PF_ROUTE, };
+struct sockproto route_proto = { PF_ROUTE, };
+
+/*ARGSUSED*/
+route_usrreq(so, req, m, nam, control)
+       register struct socket *so;
+       int req;
+       struct mbuf *m, *nam, *control;
+{
+       register int error = 0;
+       register struct rawcb *rp = sotorawcb(so);
+       int s;
+       if (req == PRU_ATTACH) {
+               MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
+               if (so->so_pcb = (caddr_t)rp)
+                       bzero(so->so_pcb, sizeof(*rp));
+
+       }
+       if (req == PRU_DETACH && rp) {
+               int af = rp->rcb_proto.sp_protocol;
+               if (af == AF_INET)
+                       route_cb.ip_count--;
+               else if (af == AF_NS)
+                       route_cb.ns_count--;
+               else if (af == AF_ISO)
+                       route_cb.iso_count--;
+               route_cb.any_count--;
+       }
+       s = splnet();
+       error = raw_usrreq(so, req, m, nam, control);
+       rp = sotorawcb(so);
+       if (req == PRU_ATTACH && rp) {
+               int af = rp->rcb_proto.sp_protocol;
+               if (error) {
+                       free((caddr_t)rp, M_PCB);
+                       splx(s);
+                       return (error);
+               }
+               if (af == AF_INET)
+                       route_cb.ip_count++;
+               else if (af == AF_NS)
+                       route_cb.ns_count++;
+               else if (af == AF_ISO)
+                       route_cb.iso_count++;
+               rp->rcb_faddr = &route_src;
+               route_cb.any_count++;
+               soisconnected(so);
+               so->so_options |= SO_USELOOPBACK;
+       }
+       splx(s);
+       return (error);
+}
+#define ROUNDUP(a) \
+       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+/*ARGSUSED*/
+route_output(m, so)
+       register struct mbuf *m;
+       struct socket *so;
+{
+       register struct rt_msghdr *rtm = 0;
+       register struct rtentry *rt = 0;
+       struct rtentry *saved_nrt = 0;
+       struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
+       struct sockaddr *ifpaddr = 0, *ifaaddr = 0;
+       caddr_t cp, lim;
+       int len, error = 0;
+       struct ifnet *ifp = 0;
+       struct ifaddr *ifa = 0;
+       struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute();
+
+#define senderr(e) { error = e; goto flush;}
+       if (m == 0 || m->m_len < sizeof(long))
+               return (ENOBUFS);
+       if ((m = m_pullup(m, sizeof(long))) == 0)
+               return (ENOBUFS);
+       if ((m->m_flags & M_PKTHDR) == 0)
+               panic("route_output");
+       len = m->m_pkthdr.len;
+       if (len < sizeof(*rtm) ||
+           len != mtod(m, struct rt_msghdr *)->rtm_msglen)
+               senderr(EINVAL);
+       R_Malloc(rtm, struct rt_msghdr *, len);
+       if (rtm == 0)
+               senderr(ENOBUFS);
+       m_copydata(m, 0, len, (caddr_t)rtm);
+       if (rtm->rtm_version != RTM_VERSION)
+               senderr(EPROTONOSUPPORT);
+       rtm->rtm_pid = curproc->p_pid;
+       lim = len + (caddr_t) rtm;
+       cp = (caddr_t) (rtm + 1);
+       if (rtm->rtm_addrs & RTA_DST) {
+               dst = (struct sockaddr *)cp;
+               ADVANCE(cp, dst);
+       } else
+               senderr(EINVAL);
+       if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim)  {
+               gate = (struct sockaddr *)cp;
+               ADVANCE(cp, gate);
+       }
+       if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim)  {
+               netmask = (struct sockaddr *)cp;
+               ADVANCE(cp, netmask);
+       }
+       if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim)  {
+               struct radix_node *t, *rn_addmask();
+               genmask = (struct sockaddr *)cp;
+               ADVANCE(cp, genmask);
+               t = rn_addmask(genmask, 1, 2);
+               if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
+                       genmask = (struct sockaddr *)(t->rn_key);
+               else
+                       senderr(ENOBUFS);
+       }
+       if ((rtm->rtm_addrs & RTA_IFP) && cp < lim)  {
+               ifpaddr = (struct sockaddr *)cp;
+               ADVANCE(cp, ifpaddr);
+       }
+       if ((rtm->rtm_addrs & RTA_IFA) && cp < lim)  {
+               ifaaddr = (struct sockaddr *)cp;
+       }
+       switch (rtm->rtm_type) {
+       case RTM_ADD:
+               if (gate == 0)
+                       senderr(EINVAL);
+               error = rtrequest(RTM_ADD, dst, gate, netmask,
+                                       rtm->rtm_flags, &saved_nrt);
+               if (error == 0 && saved_nrt) {
+                       rt_setmetrics(rtm->rtm_inits,
+                               &rtm->rtm_rmx, &saved_nrt->rt_rmx);
+                       saved_nrt->rt_refcnt--;
+                       saved_nrt->rt_genmask = genmask;
+               }
+               break;
+
+       case RTM_DELETE:
+               error = rtrequest(RTM_DELETE, dst, gate, netmask,
+                               rtm->rtm_flags, (struct rtentry **)0);
+               break;
+
+       case RTM_GET:
+       case RTM_CHANGE:
+       case RTM_LOCK:
+               rt = rtalloc1(dst, 0);
+               if (rt == 0)
+                       senderr(ESRCH);
+               if (rtm->rtm_type != RTM_GET) {
+                       if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0)
+                               senderr(ESRCH);
+                       if (rt->rt_nodes->rn_dupedkey &&
+                           (netmask == 0 ||
+                            Bcmp(netmask, rt_mask(rt), netmask->sa_len)))
+                               senderr(ETOOMANYREFS);
+               }
+               switch(rtm->rtm_type) {
+
+               case RTM_GET:
+                       dst = rt_key(rt); len = sizeof(*rtm);
+                       ADVANCE(len, dst);
+                       rtm->rtm_addrs |= RTA_DST;
+                       if (gate = rt->rt_gateway) {
+                               ADVANCE(len, gate);
+                               rtm->rtm_addrs |= RTA_GATEWAY;
+                       } else
+                               rtm->rtm_addrs &= ~RTA_GATEWAY;
+                       if (netmask = rt_mask(rt)) {
+                               ADVANCE(len, netmask);
+                               rtm->rtm_addrs |= RTA_NETMASK;
+                       } else
+                               rtm->rtm_addrs &= ~RTA_NETMASK;
+                       if (genmask = rt->rt_genmask) {
+                               ADVANCE(len, genmask);
+                               rtm->rtm_addrs |= RTA_GENMASK;
+                       } else
+                               rtm->rtm_addrs &= ~RTA_GENMASK;
+                       if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
+                               if (rt->rt_ifp == 0)
+                                       goto badif;
+                               for (ifa = rt->rt_ifp->if_addrlist;
+                                   ifa && ifa->ifa_addr->sa_family != AF_LINK;
+                                    ifa = ifa->ifa_next){}
+                               if (ifa && rt->rt_ifa) {
+                                       ifpaddr = ifa->ifa_addr;
+                                       ADVANCE(len, ifpaddr);
+                                       ifaaddr = rt->rt_ifa->ifa_addr;
+                                       ADVANCE(len, ifaaddr);
+                                       rtm->rtm_addrs |= RTA_IFP | RTA_IFA;
+                               } else {
+                               badif:  ifpaddr = 0;
+                                       rtm->rtm_addrs &= ~(RTA_IFP | RTA_IFA);
+                               }
+                       }
+                       if (len > rtm->rtm_msglen) {
+                               struct rt_msghdr *new_rtm;
+                               R_Malloc(new_rtm, struct rt_msghdr *, len);
+                               if (new_rtm == 0)
+                                       senderr(ENOBUFS);
+                               Bcopy(rtm, new_rtm, rtm->rtm_msglen);
+                               Free(rtm); rtm = new_rtm;
+                       }
+                       rtm->rtm_msglen = len;
+                       rtm->rtm_flags = rt->rt_flags;
+                       rtm->rtm_rmx = rt->rt_rmx;
+                       cp = (caddr_t) (1 + rtm);
+                       len = ROUNDUP(dst->sa_len); 
+                       Bcopy(dst, cp, len); cp += len;
+                       if (gate) {
+                           len = ROUNDUP(gate->sa_len);
+                           Bcopy(gate, cp, len); cp += len;
+                       }
+                       if (netmask) {
+                           len = ROUNDUP(netmask->sa_len);
+                           Bcopy(netmask, cp, len); cp += len;
+                       }
+                       if (genmask) {
+                           len = ROUNDUP(genmask->sa_len);
+                           Bcopy(genmask, cp, len); cp += len;
+                       }
+                       if (ifpaddr) {
+                           len = ROUNDUP(ifpaddr->sa_len);
+                           Bcopy(ifpaddr, cp, len); cp += len;
+                           len = ROUNDUP(ifaaddr->sa_len);
+                           Bcopy(ifaaddr, cp, len); cp += len;
+                       }
+                       break;
+
+               case RTM_CHANGE:
+                       if (gate &&
+                           (gate->sa_len > (len = rt->rt_gateway->sa_len)))
+                               senderr(EDQUOT);
+                       /* new gateway could require new ifaddr, ifp;
+                          flags may also be different; ifp may be specified
+                          by ll sockaddr when protocol address is ambiguous */
+                       if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
+                           (ifp = ifa->ifa_ifp))
+                               ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
+                                                       ifp);
+                       else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
+                                (ifa = ifa_ifwithroute(rt->rt_flags,
+                                                       rt_key(rt), gate)))
+                               ifp = ifa->ifa_ifp;
+                       if (ifa) {
+                               register struct ifaddr *oifa = rt->rt_ifa;
+                               if (oifa != ifa) {
+                                   if (oifa && oifa->ifa_rtrequest)
+                                       oifa->ifa_rtrequest(RTM_DELETE,
+                                                               rt, gate);
+                                   rt->rt_ifa = ifa;
+                                   rt->rt_ifp = ifp;
+                               }
+                       }
+                       if (gate)
+                               Bcopy(gate, rt->rt_gateway, len);
+                       rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
+                                       &rt->rt_rmx);
+                       if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
+                              rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
+                       if (genmask)
+                               rt->rt_genmask = genmask;
+                       /*
+                        * Fall into
+                        */
+               case RTM_LOCK:
+                       rt->rt_rmx.rmx_locks |=
+                               (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
+                       rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
+                       break;
+               }
+               goto cleanup;
+
+       default:
+               senderr(EOPNOTSUPP);
+       }
+
+flush:
+       if (rtm) {
+               if (error)
+                       rtm->rtm_errno = error;
+               else 
+                       rtm->rtm_flags |= RTF_DONE;
+       }
+cleanup:
+       if (rt)
+               rtfree(rt);
+    {
+       register struct rawcb *rp = 0;
+       /*
+        * Check to see if we don't want our own messages.
+        */
+       if ((so->so_options & SO_USELOOPBACK) == 0) {
+               if (route_cb.any_count <= 1) {
+                       if (rtm)
+                               Free(rtm);
+                       m_freem(m);
+                       return (error);
+               }
+               /* There is another listener, so construct message */
+               rp = sotorawcb(so);
+       }
+       if (rtm) {
+               m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
+               Free(rtm);
+       }
+       if (rp)
+               rp->rcb_proto.sp_family = 0; /* Avoid us */
+       if (dst)
+               route_proto.sp_protocol = dst->sa_family;
+       raw_input(m, &route_proto, &route_src, &route_dst);
+       if (rp)
+               rp->rcb_proto.sp_family = PF_ROUTE;
+    }
+       return (error);
+}
+
+rt_setmetrics(which, in, out)
+       u_long which;
+       register struct rt_metrics *in, *out;
+{
+#define metric(f, e) if (which & (f)) out->e = in->e;
+       metric(RTV_RPIPE, rmx_recvpipe);
+       metric(RTV_SPIPE, rmx_sendpipe);
+       metric(RTV_SSTHRESH, rmx_ssthresh);
+       metric(RTV_RTT, rmx_rtt);
+       metric(RTV_RTTVAR, rmx_rttvar);
+       metric(RTV_HOPCOUNT, rmx_hopcount);
+       metric(RTV_MTU, rmx_mtu);
+       metric(RTV_EXPIRE, rmx_expire);
+#undef metric
+}
+
+/*
+ * Copy data from a buffer back into the indicated mbuf chain,
+ * starting "off" bytes from the beginning, extending the mbuf
+ * chain if necessary.
+ */
+m_copyback(m0, off, len, cp)
+       struct  mbuf *m0;
+       register int off;
+       register int len;
+       caddr_t cp;
+
+{
+       register int mlen;
+       register struct mbuf *m = m0, *n;
+       int totlen = 0;
+
+       if (m0 == 0)
+               return;
+       while (off > (mlen = m->m_len)) {
+               off -= mlen;
+               totlen += mlen;
+               if (m->m_next == 0) {
+                       n = m_getclr(M_DONTWAIT, m->m_type);
+                       if (n == 0)
+                               goto out;
+                       n->m_len = min(MLEN, len + off);
+                       m->m_next = n;
+               }
+               m = m->m_next;
+       }
+       while (len > 0) {
+               mlen = min (m->m_len - off, len);
+               bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
+               cp += mlen;
+               len -= mlen;
+               mlen += off;
+               off = 0;
+               totlen += mlen;
+               if (len == 0)
+                       break;
+               if (m->m_next == 0) {
+                       n = m_get(M_DONTWAIT, m->m_type);
+                       if (n == 0)
+                               break;
+                       n->m_len = min(MLEN, len);
+                       m->m_next = n;
+               }
+               m = m->m_next;
+       }
+out:   if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
+               m->m_pkthdr.len = totlen;
+}
+
+/* 
+ * The miss message and losing message are very similar.
+ */
+
+rt_missmsg(type, dst, gate, mask, src, flags, error)
+register struct sockaddr *dst;
+struct sockaddr *gate, *mask, *src;
+{
+       register struct rt_msghdr *rtm;
+       register struct mbuf *m;
+       int dlen = ROUNDUP(dst->sa_len);
+       int len = dlen + sizeof(*rtm);
+
+       if (route_cb.any_count == 0)
+               return;
+       m = m_gethdr(M_DONTWAIT, MT_DATA);
+       if (m == 0)
+               return;
+       m->m_pkthdr.len = m->m_len = min(len, MHLEN);
+       m->m_pkthdr.rcvif = 0;
+       rtm = mtod(m, struct rt_msghdr *);
+       bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/
+       rtm->rtm_flags = RTF_DONE | flags;
+       rtm->rtm_msglen = len;
+       rtm->rtm_version = RTM_VERSION;
+       rtm->rtm_type = type;
+       rtm->rtm_addrs = RTA_DST;
+       if (type == RTM_OLDADD || type == RTM_OLDDEL) {
+               rtm->rtm_pid = curproc->p_pid;
+       }
+       m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst);
+       if (gate) {
+               dlen = ROUNDUP(gate->sa_len);
+               m_copyback(m, len ,  dlen, (caddr_t)gate);
+               len += dlen;
+               rtm->rtm_addrs |= RTA_GATEWAY;
+       }
+       if (mask) {
+               dlen = ROUNDUP(mask->sa_len);
+               m_copyback(m, len ,  dlen, (caddr_t)mask);
+               len += dlen;
+               rtm->rtm_addrs |= RTA_NETMASK;
+       }
+       if (src) {
+               dlen = ROUNDUP(src->sa_len);
+               m_copyback(m, len ,  dlen, (caddr_t)src);
+               len += dlen;
+               rtm->rtm_addrs |= RTA_AUTHOR;
+       }
+       if (m->m_pkthdr.len != len) {
+               m_freem(m);
+               return;
+       }
+       rtm->rtm_errno = error;
+       rtm->rtm_msglen = len;
+       route_proto.sp_protocol = dst->sa_family;
+       raw_input(m, &route_proto, &route_src, &route_dst);
+}
+
+#include "kinfo.h"
+struct walkarg {
+       int     w_op, w_arg;
+       int     w_given, w_needed;
+       caddr_t w_where;
+       struct  {
+               struct rt_msghdr m_rtm;
+               char    m_sabuf[128];
+       } w_m;
+#define w_rtm w_m.m_rtm
+};
+/*
+ * This is used in dumping the kernel table via getkinfo().
+ */
+rt_dumpentry(rn, w)
+       struct radix_node *rn;
+       register struct walkarg *w;
+{
+       register struct sockaddr *sa;
+       int n, error;
+
+    for (; rn; rn = rn->rn_dupedkey) {
+       int count = 0, size = sizeof(w->w_rtm);
+       register struct rtentry *rt = (struct rtentry *)rn;
+
+       if (rn->rn_flags & RNF_ROOT)
+               continue;
+       if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg))
+               continue;
+#define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); }
+       w->w_rtm.rtm_addrs = 0;
+       if (sa = rt_key(rt))
+               next(RTA_DST, ROUNDUP(sa->sa_len));
+       if (sa = rt->rt_gateway)
+               next(RTA_GATEWAY, ROUNDUP(sa->sa_len));
+       if (sa = rt_mask(rt))
+               next(RTA_NETMASK, ROUNDUP(sa->sa_len));
+       if (sa = rt->rt_genmask)
+               next(RTA_GENMASK, ROUNDUP(sa->sa_len));
+       w->w_needed += size;
+       if (w->w_where == NULL || w->w_needed > 0)
+               continue;
+       w->w_rtm.rtm_msglen = size;
+       w->w_rtm.rtm_flags = rt->rt_flags;
+       w->w_rtm.rtm_use = rt->rt_use;
+       w->w_rtm.rtm_rmx = rt->rt_rmx;
+       w->w_rtm.rtm_index = rt->rt_ifp->if_index;
+#undef next
+#define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;}
+       if (size <= sizeof(w->w_m)) {
+               register caddr_t cp = (caddr_t)(w->w_m.m_sabuf);
+               if (sa = rt_key(rt))
+                       next(ROUNDUP(sa->sa_len));
+               if (sa = rt->rt_gateway)
+                       next(ROUNDUP(sa->sa_len));
+               if (sa = rt_mask(rt))
+                       next(ROUNDUP(sa->sa_len));
+               if (sa = rt->rt_genmask)
+                       next(ROUNDUP(sa->sa_len));
+#undef next
+#define next(s, l) {n = (l); \
+    if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \
+    w->w_where += n;}
+
+               next(&w->w_m, size); /* Copy rtmsg and sockaddrs back */
+               continue;
+       }
+       next(&w->w_rtm, sizeof(w->w_rtm));
+       if (sa = rt_key(rt))
+               next(sa, ROUNDUP(sa->sa_len));
+       if (sa = rt->rt_gateway)
+               next(sa, ROUNDUP(sa->sa_len));
+       if (sa = rt_mask(rt))
+               next(sa, ROUNDUP(sa->sa_len));
+       if (sa = rt->rt_genmask)
+               next(sa, ROUNDUP(sa->sa_len));
+    }
+       return (0);
+#undef next
+}
+
+kinfo_rtable(op, where, given, arg, needed)
+       int     op, arg;
+       caddr_t where;
+       int     *given, *needed;
+{
+       register struct radix_node_head *rnh;
+       int     s, error = 0;
+       u_char  af = ki_af(op);
+       struct  walkarg w;
+
+       op &= 0xffff;
+       if (op != KINFO_RT_DUMP && op != KINFO_RT_FLAGS)
+               return (EINVAL);
+
+       Bzero(&w, sizeof(w));
+       if ((w.w_where = where) && given)
+               w.w_given = *given;
+       w.w_needed = 0 - w.w_given;
+       w.w_arg = arg;
+       w.w_op = op;
+       w.w_rtm.rtm_version = RTM_VERSION;
+       w.w_rtm.rtm_type = RTM_GET;
+
+       s = splnet();
+       for (rnh = radix_node_head; rnh; rnh = rnh->rnh_next) {
+               if (rnh->rnh_af == 0)
+                       continue;
+               if (af && af != rnh->rnh_af)
+                       continue;
+               error = rt_walk(rnh->rnh_treetop, rt_dumpentry, &w);
+               if (error)
+                       break;
+       }
+       w.w_needed += w.w_given;
+       if (where && given)
+               *given = w.w_where - where;
+       else
+               w.w_needed = (11 * w.w_needed) / 10;
+       *needed = w.w_needed;
+       splx(s);
+       return (error);
+}
+
+rt_walk(rn, f, w)
+       register struct radix_node *rn;
+       register int (*f)();
+       struct walkarg *w;
+{
+       int error;
+       for (;;) {
+               while (rn->rn_b >= 0)
+                       rn = rn->rn_l;  /* First time through node, go left */
+               if (error = (*f)(rn, w))
+                       return (error); /* Process Leaf */
+               while (rn->rn_p->rn_r == rn) {  /* if coming back from right */
+                       rn = rn->rn_p;          /* go back up */
+                       if (rn->rn_flags & RNF_ROOT)
+                               return 0;
+               }
+               rn = rn->rn_p->rn_r;            /* otherwise, go right*/
+       }
+}
+
+/*
+ * Definitions of protocols supported in the ROUTE domain.
+ */
+
+int    raw_init(),raw_usrreq(),raw_input(),raw_ctlinput();
+extern struct domain routedomain;              /* or at least forward */
+
+struct protosw routesw[] = {
+{ SOCK_RAW,    &routedomain,   0,              PR_ATOMIC|PR_ADDR,
+  raw_input,   route_output,   raw_ctlinput,   0,
+  route_usrreq,
+  raw_init,    0,              0,              0,
+}
+};
+
+int    unp_externalize(), unp_dispose();
+
+struct domain routedomain =
+    { PF_ROUTE, "route", 0, 0, 0,
+      routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
diff --git a/usr/src/sys.386bsd/net/slcompress.c b/usr/src/sys.386bsd/net/slcompress.c
new file mode 100644 (file)
index 0000000..81b3543
--- /dev/null
@@ -0,0 +1,535 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)slcompress.c        7.7 (Berkeley) 5/7/91
+ */
+
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ *     - Initial distribution.
+ *
+ * static char rcsid[] =
+ * "$Header: slcompress.c,v 1.19 89/12/31 08:52:59 van Exp $";
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include "slcompress.h"
+
+#ifndef SL_NO_STATS
+#define INCR(counter) ++comp->counter;
+#else
+#define INCR(counter)
+#endif
+
+#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
+#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
+#ifndef KERNEL
+#define ovbcopy bcopy
+#endif
+
+
+void
+sl_compress_init(comp)
+       struct slcompress *comp;
+{
+       register u_int i;
+       register struct cstate *tstate = comp->tstate;
+
+       bzero((char *)comp, sizeof(*comp));
+       for (i = MAX_STATES - 1; i > 0; --i) {
+               tstate[i].cs_id = i;
+               tstate[i].cs_next = &tstate[i - 1];
+       }
+       tstate[0].cs_next = &tstate[MAX_STATES - 1];
+       tstate[0].cs_id = 0;
+       comp->last_cs = &tstate[0];
+       comp->last_recv = 255;
+       comp->last_xmit = 255;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+       if ((u_short)(n) >= 256) { \
+               *cp++ = 0; \
+               cp[1] = (n); \
+               cp[0] = (n) >> 8; \
+               cp += 2; \
+       } else { \
+               *cp++ = (n); \
+       } \
+}
+#define ENCODEZ(n) { \
+       if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+               *cp++ = 0; \
+               cp[1] = (n); \
+               cp[0] = (n) >> 8; \
+               cp += 2; \
+       } else { \
+               *cp++ = (n); \
+       } \
+}
+
+#define DECODEL(f) { \
+       if (*cp == 0) {\
+               (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
+               cp += 3; \
+       } else { \
+               (f) = htonl(ntohl(f) + (u_long)*cp++); \
+       } \
+}
+
+#define DECODES(f) { \
+       if (*cp == 0) {\
+               (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
+               cp += 3; \
+       } else { \
+               (f) = htons(ntohs(f) + (u_long)*cp++); \
+       } \
+}
+
+#define DECODEU(f) { \
+       if (*cp == 0) {\
+               (f) = htons((cp[1] << 8) | cp[2]); \
+               cp += 3; \
+       } else { \
+               (f) = htons((u_long)*cp++); \
+       } \
+}
+
+
+u_char
+sl_compress_tcp(m, ip, comp, compress_cid)
+       struct mbuf *m;
+       register struct ip *ip;
+       struct slcompress *comp;
+       int compress_cid;
+{
+       register struct cstate *cs = comp->last_cs->cs_next;
+       register u_int hlen = ip->ip_hl;
+       register struct tcphdr *oth;
+       register struct tcphdr *th;
+       register u_int deltaS, deltaA;
+       register u_int changes = 0;
+       u_char new_seq[16];
+       register u_char *cp = new_seq;
+
+       /*
+        * Bail if this is an IP fragment or if the TCP packet isn't
+        * `compressible' (i.e., ACK isn't set or some other control bit is
+        * set).  (We assume that the caller has already made sure the
+        * packet is IP proto TCP).
+        */
+       if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
+               return (TYPE_IP);
+
+       th = (struct tcphdr *)&((int *)ip)[hlen];
+       if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
+               return (TYPE_IP);
+       /*
+        * Packet is compressible -- we're going to send either a
+        * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
+        * to locate (or create) the connection state.  Special case the
+        * most recently used connection since it's most likely to be used
+        * again & we don't have to do any reordering if it's used.
+        */
+       INCR(sls_packets)
+       if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+           ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+           *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
+               /*
+                * Wasn't the first -- search for it.
+                *
+                * States are kept in a circularly linked list with
+                * last_cs pointing to the end of the list.  The
+                * list is kept in lru order by moving a state to the
+                * head of the list whenever it is referenced.  Since
+                * the list is short and, empirically, the connection
+                * we want is almost always near the front, we locate
+                * states via linear search.  If we don't find a state
+                * for the datagram, the oldest state is (re-)used.
+                */
+               register struct cstate *lcs;
+               register struct cstate *lastcs = comp->last_cs;
+
+               do {
+                       lcs = cs; cs = cs->cs_next;
+                       INCR(sls_searches)
+                       if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+                           && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+                           && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl])
+                               goto found;
+               } while (cs != lastcs);
+
+               /*
+                * Didn't find it -- re-use oldest cstate.  Send an
+                * uncompressed packet that tells the other side what
+                * connection number we're using for this conversation.
+                * Note that since the state list is circular, the oldest
+                * state points to the newest and we only need to set
+                * last_cs to update the lru linkage.
+                */
+               INCR(sls_misses)
+               comp->last_cs = lcs;
+               hlen += th->th_off;
+               hlen <<= 2;
+               goto uncompressed;
+
+       found:
+               /*
+                * Found it -- move to the front on the connection list.
+                */
+               if (cs == lastcs)
+                       comp->last_cs = lcs;
+               else {
+                       lcs->cs_next = cs->cs_next;
+                       cs->cs_next = lastcs->cs_next;
+                       lastcs->cs_next = cs;
+               }
+       }
+
+       /*
+        * Make sure that only what we expect to change changed. The first
+        * line of the `if' checks the IP protocol version, header length &
+        * type of service.  The 2nd line checks the "Don't fragment" bit.
+        * The 3rd line checks the time-to-live and protocol (the protocol
+        * check is unnecessary but costless).  The 4th line checks the TCP
+        * header length.  The 5th line checks IP options, if any.  The 6th
+        * line checks TCP options, if any.  If any of these things are
+        * different between the previous & current datagram, we send the
+        * current datagram `uncompressed'.
+        */
+       oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
+       deltaS = hlen;
+       hlen += th->th_off;
+       hlen <<= 2;
+
+       if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
+           ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
+           ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
+           th->th_off != oth->th_off ||
+           (deltaS > 5 &&
+            BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
+           (th->th_off > 5 &&
+            BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
+               goto uncompressed;
+
+       /*
+        * Figure out which of the changing fields changed.  The
+        * receiver expects changes in the order: urgent, window,
+        * ack, seq (the order minimizes the number of temporaries
+        * needed in this section of code).
+        */
+       if (th->th_flags & TH_URG) {
+               deltaS = ntohs(th->th_urp);
+               ENCODEZ(deltaS);
+               changes |= NEW_U;
+       } else if (th->th_urp != oth->th_urp)
+               /* argh! URG not set but urp changed -- a sensible
+                * implementation should never do this but RFC793
+                * doesn't prohibit the change so we have to deal
+                * with it. */
+                goto uncompressed;
+
+       if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) {
+               ENCODE(deltaS);
+               changes |= NEW_W;
+       }
+
+       if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) {
+               if (deltaA > 0xffff)
+                       goto uncompressed;
+               ENCODE(deltaA);
+               changes |= NEW_A;
+       }
+
+       if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) {
+               if (deltaS > 0xffff)
+                       goto uncompressed;
+               ENCODE(deltaS);
+               changes |= NEW_S;
+       }
+
+       switch(changes) {
+
+       case 0:
+               /*
+                * Nothing changed. If this packet contains data and the
+                * last one didn't, this is probably a data packet following
+                * an ack (normal on an interactive connection) and we send
+                * it compressed.  Otherwise it's probably a retransmit,
+                * retransmitted ack or window probe.  Send it uncompressed
+                * in case the other side missed the compressed version.
+                */
+               if (ip->ip_len != cs->cs_ip.ip_len &&
+                   ntohs(cs->cs_ip.ip_len) == hlen)
+                       break;
+
+               /* (fall through) */
+
+       case SPECIAL_I:
+       case SPECIAL_D:
+               /*
+                * actual changes match one of our special case encodings --
+                * send packet uncompressed.
+                */
+               goto uncompressed;
+
+       case NEW_S|NEW_A:
+               if (deltaS == deltaA &&
+                   deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+                       /* special case for echoed terminal traffic */
+                       changes = SPECIAL_I;
+                       cp = new_seq;
+               }
+               break;
+
+       case NEW_S:
+               if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+                       /* special case for data xfer */
+                       changes = SPECIAL_D;
+                       cp = new_seq;
+               }
+               break;
+       }
+
+       deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+       if (deltaS != 1) {
+               ENCODEZ(deltaS);
+               changes |= NEW_I;
+       }
+       if (th->th_flags & TH_PUSH)
+               changes |= TCP_PUSH_BIT;
+       /*
+        * Grab the cksum before we overwrite it below.  Then update our
+        * state with this packet's header.
+        */
+       deltaA = ntohs(th->th_sum);
+       BCOPY(ip, &cs->cs_ip, hlen);
+
+       /*
+        * We want to use the original packet as our compressed packet.
+        * (cp - new_seq) is the number of bytes we need for compressed
+        * sequence numbers.  In addition we need one byte for the change
+        * mask, one for the connection id and two for the tcp checksum.
+        * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
+        * many bytes of the original packet to toss so subtract the two to
+        * get the new packet size.
+        */
+       deltaS = cp - new_seq;
+       cp = (u_char *)ip;
+       if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
+               comp->last_xmit = cs->cs_id;
+               hlen -= deltaS + 4;
+               cp += hlen;
+               *cp++ = changes | NEW_C;
+               *cp++ = cs->cs_id;
+       } else {
+               hlen -= deltaS + 3;
+               cp += hlen;
+               *cp++ = changes;
+       }
+       m->m_len -= hlen;
+       m->m_data += hlen;
+       *cp++ = deltaA >> 8;
+       *cp++ = deltaA;
+       BCOPY(new_seq, cp, deltaS);
+       INCR(sls_compressed)
+       return (TYPE_COMPRESSED_TCP);
+
+       /*
+        * Update connection state cs & send uncompressed packet ('uncompressed'
+        * means a regular ip/tcp packet but with the 'conversation id' we hope
+        * to use on future compressed packets in the protocol field).
+        */
+uncompressed:
+       BCOPY(ip, &cs->cs_ip, hlen);
+       ip->ip_p = cs->cs_id;
+       comp->last_xmit = cs->cs_id;
+       return (TYPE_UNCOMPRESSED_TCP);
+}
+
+
+int
+sl_uncompress_tcp(bufp, len, type, comp)
+       u_char **bufp;
+       int len;
+       u_int type;
+       struct slcompress *comp;
+{
+       register u_char *cp;
+       register u_int hlen, changes;
+       register struct tcphdr *th;
+       register struct cstate *cs;
+       register struct ip *ip;
+
+       switch (type) {
+
+       case TYPE_UNCOMPRESSED_TCP:
+               ip = (struct ip *) *bufp;
+               if (ip->ip_p >= MAX_STATES)
+                       goto bad;
+               cs = &comp->rstate[comp->last_recv = ip->ip_p];
+               comp->flags &=~ SLF_TOSS;
+               ip->ip_p = IPPROTO_TCP;
+               hlen = ip->ip_hl;
+               hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off;
+               hlen <<= 2;
+               BCOPY(ip, &cs->cs_ip, hlen);
+               cs->cs_ip.ip_sum = 0;
+               cs->cs_hlen = hlen;
+               INCR(sls_uncompressedin)
+               return (len);
+
+       default:
+               goto bad;
+
+       case TYPE_COMPRESSED_TCP:
+               break;
+       }
+       /* We've got a compressed packet. */
+       INCR(sls_compressedin)
+       cp = *bufp;
+       changes = *cp++;
+       if (changes & NEW_C) {
+               /* Make sure the state index is in range, then grab the state.
+                * If we have a good state index, clear the 'discard' flag. */
+               if (*cp >= MAX_STATES)
+                       goto bad;
+
+               comp->flags &=~ SLF_TOSS;
+               comp->last_recv = *cp++;
+       } else {
+               /* this packet has an implicit state index.  If we've
+                * had a line error since the last time we got an
+                * explicit state index, we have to toss the packet. */
+               if (comp->flags & SLF_TOSS) {
+                       INCR(sls_tossed)
+                       return (0);
+               }
+       }
+       cs = &comp->rstate[comp->last_recv];
+       hlen = cs->cs_ip.ip_hl << 2;
+       th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
+       th->th_sum = htons((*cp << 8) | cp[1]);
+       cp += 2;
+       if (changes & TCP_PUSH_BIT)
+               th->th_flags |= TH_PUSH;
+       else
+               th->th_flags &=~ TH_PUSH;
+
+       switch (changes & SPECIALS_MASK) {
+       case SPECIAL_I:
+               {
+               register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+               th->th_ack = htonl(ntohl(th->th_ack) + i);
+               th->th_seq = htonl(ntohl(th->th_seq) + i);
+               }
+               break;
+
+       case SPECIAL_D:
+               th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
+                                  - cs->cs_hlen);
+               break;
+
+       default:
+               if (changes & NEW_U) {
+                       th->th_flags |= TH_URG;
+                       DECODEU(th->th_urp)
+               } else
+                       th->th_flags &=~ TH_URG;
+               if (changes & NEW_W)
+                       DECODES(th->th_win)
+               if (changes & NEW_A)
+                       DECODEL(th->th_ack)
+               if (changes & NEW_S)
+                       DECODEL(th->th_seq)
+               break;
+       }
+       if (changes & NEW_I) {
+               DECODES(cs->cs_ip.ip_id)
+       } else
+               cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
+
+       /*
+        * At this point, cp points to the first byte of data in the
+        * packet.  If we're not aligned on a 4-byte boundary, copy the
+        * data down so the ip & tcp headers will be aligned.  Then back up
+        * cp by the tcp/ip header length to make room for the reconstructed
+        * header (we assume the packet we were handed has enough space to
+        * prepend 128 bytes of header).  Adjust the length to account for
+        * the new header & fill in the IP total length.
+        */
+       len -= (cp - *bufp);
+       if (len < 0)
+               /* we must have dropped some characters (crc should detect
+                * this but the old slip framing won't) */
+               goto bad;
+
+       if ((int)cp & 3) {
+               if (len > 0)
+                       (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
+               cp = (u_char *)((int)cp &~ 3);
+       }
+       cp -= cs->cs_hlen;
+       len += cs->cs_hlen;
+       cs->cs_ip.ip_len = htons(len);
+       BCOPY(&cs->cs_ip, cp, cs->cs_hlen);
+       *bufp = cp;
+
+       /* recompute the ip header checksum */
+       {
+               register u_short *bp = (u_short *)cp;
+               for (changes = 0; hlen > 0; hlen -= 2)
+                       changes += *bp++;
+               changes = (changes & 0xffff) + (changes >> 16);
+               changes = (changes & 0xffff) + (changes >> 16);
+               ((struct ip *)cp)->ip_sum = ~ changes;
+       }
+       return (len);
+bad:
+       comp->flags |= SLF_TOSS;
+       INCR(sls_errorin)
+       return (0);
+}
diff --git a/usr/src/sys.386bsd/net/slcompress.h b/usr/src/sys.386bsd/net/slcompress.h
new file mode 100644 (file)
index 0000000..f799706
--- /dev/null
@@ -0,0 +1,157 @@
+/*     slcompress.h    7.4     90/06/28        */
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ *     - Initial distribution.
+ */
+
+#define MAX_STATES 16          /* must be > 2 and < 256 */
+#define MAX_HDR MLEN           /* XXX 4bsd-ism: should really be 128 */
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits).  The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet.  The next two octets are the TCP checksum
+ * from the original datagram.  The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ * 
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID.  (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.)  Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0.  (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type.  There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows.  Top
+ * three bits are actual packet type.  For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C  0x40    /* flag bits for what changed in a packet */
+#define NEW_I  0x20
+#define NEW_S  0x08
+#define NEW_A  0x04
+#define NEW_W  0x02
+#define NEW_U  0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U)          /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)    /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+
+/*
+ * "state" data for each active tcp conversation on the wire.  This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+       struct cstate *cs_next; /* next most recently used cstate (xmit only) */
+       u_short cs_hlen;        /* size of hdr (receive only) */
+       u_char cs_id;           /* connection # associated with this state */
+       u_char cs_filler;
+       union {
+               char csu_hdr[MAX_HDR];
+               struct ip csu_ip;       /* ip/tcp hdr from most recent packet */
+       } slcs_u;
+};
+#define cs_ip slcs_u.csu_ip
+#define cs_hdr slcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these
+ * per line).
+ */
+struct slcompress {
+       struct cstate *last_cs; /* most recently used tstate */
+       u_char last_recv;       /* last rcvd conn. id */
+       u_char last_xmit;       /* last sent conn. id */
+       u_short flags;
+#ifndef SL_NO_STATS
+       int sls_packets;        /* outbound packets */
+       int sls_compressed;     /* outbound compressed packets */
+       int sls_searches;       /* searches for connection state */
+       int sls_misses;         /* times couldn't find conn. state */
+       int sls_uncompressedin; /* inbound uncompressed packets */
+       int sls_compressedin;   /* inbound compressed packets */
+       int sls_errorin;        /* inbound unknown type packets */
+       int sls_tossed;         /* inbound packets tossed because of error */
+#endif
+       struct cstate tstate[MAX_STATES];       /* xmit connection states */
+       struct cstate rstate[MAX_STATES];       /* receive connection states */
+};
+/* flag values */
+#define SLF_TOSS 1             /* tossing rcvd frames because of input err */
+
+extern void sl_compress_init(/* struct slcompress * */);
+extern u_char sl_compress_tcp(/* struct mbuf *, struct ip *,
+                               struct slcompress *, int compress_cid_flag */);
+extern int sl_uncompress_tcp(/* u_char **, int,  u_char, struct slcompress * */);
diff --git a/usr/src/sys.386bsd/netinet/icmp_var.h b/usr/src/sys.386bsd/netinet/icmp_var.h
new file mode 100644 (file)
index 0000000..4e311e4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)icmp_var.h  7.5 (Berkeley) 6/28/90
+ */
+
+/*
+ * Variables related to this implementation
+ * of the internet control message protocol.
+ */
+struct icmpstat {
+/* statistics related to icmp packets generated */
+       int     icps_error;             /* # of calls to icmp_error */
+       int     icps_oldshort;          /* no error 'cuz old ip too short */
+       int     icps_oldicmp;           /* no error 'cuz old was icmp */
+       int     icps_outhist[ICMP_MAXTYPE + 1];
+/* statistics related to input messages processed */
+       int     icps_badcode;           /* icmp_code out of range */
+       int     icps_tooshort;          /* packet < ICMP_MINLEN */
+       int     icps_checksum;          /* bad checksum */
+       int     icps_badlen;            /* calculated bound mismatch */
+       int     icps_reflect;           /* number of responses */
+       int     icps_inhist[ICMP_MAXTYPE + 1];
+};
+
+#ifdef KERNEL
+struct icmpstat icmpstat;
+#endif
diff --git a/usr/src/sys.386bsd/netinet/if_ether.c b/usr/src/sys.386bsd/netinet/if_ether.c
new file mode 100644 (file)
index 0000000..d4e60a5
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_ether.c  7.13 (Berkeley) 10/31/90
+ */
+
+/*
+ * Ethernet address resolution protocol.
+ * TODO:
+ *     run at splnet (add ARP protocol intr.)
+ *     link entries onto hash chains, keep free list
+ *     add "inuse/lock" bit (or ref. count) along with valid bit
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "time.h"
+#include "kernel.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "syslog.h"
+
+#include "../net/if.h"
+#include "in.h"
+#include "in_systm.h"
+#include "in_var.h"
+#include "ip.h"
+#include "if_ether.h"
+
+#ifdef GATEWAY
+#define        ARPTAB_BSIZ     16              /* bucket size */
+#define        ARPTAB_NB       37              /* number of buckets */
+#else
+#define        ARPTAB_BSIZ     9               /* bucket size */
+#define        ARPTAB_NB       19              /* number of buckets */
+#endif
+#define        ARPTAB_SIZE     (ARPTAB_BSIZ * ARPTAB_NB)
+struct arptab arptab[ARPTAB_SIZE];
+int    arptab_size = ARPTAB_SIZE;      /* for arp command */
+
+/*
+ * ARP trailer negotiation.  Trailer protocol is not IP specific,
+ * but ARP request/response use IP addresses.
+ */
+#define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
+
+#define        ARPTAB_HASH(a) \
+       ((u_long)(a) % ARPTAB_NB)
+
+#define        ARPTAB_LOOK(at,addr) { \
+       register n; \
+       at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
+       for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
+               if (at->at_iaddr.s_addr == addr) \
+                       break; \
+       if (n >= ARPTAB_BSIZ) \
+               at = 0; \
+}
+
+/* timer values */
+#define        ARPT_AGE        (60*1)  /* aging timer, 1 min. */
+#define        ARPT_KILLC      20      /* kill completed entry in 20 mins. */
+#define        ARPT_KILLI      3       /* kill incomplete entry in 3 minutes */
+
+extern struct ifnet loif;
+
+/*
+ * Timeout routine.  Age arp_tab entries once a minute.
+ */
+arptimer()
+{
+       register struct arptab *at;
+       register i;
+
+       timeout(arptimer, (caddr_t)0, ARPT_AGE * hz);
+       at = &arptab[0];
+       for (i = 0; i < ARPTAB_SIZE; i++, at++) {
+               if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
+                       continue;
+               if (++at->at_timer < ((at->at_flags&ATF_COM) ?
+                   ARPT_KILLC : ARPT_KILLI))
+                       continue;
+               /* timer has expired, clear entry */
+               arptfree(at);
+       }
+}
+
+/*
+ * Broadcast an ARP packet, asking who has addr on interface ac.
+ */
+arpwhohas(ac, addr)
+       register struct arpcom *ac;
+       struct in_addr *addr;
+{
+       register struct mbuf *m;
+       register struct ether_header *eh;
+       register struct ether_arp *ea;
+       struct sockaddr sa;
+
+       if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+               return;
+       m->m_len = sizeof(*ea);
+       m->m_pkthdr.len = sizeof(*ea);
+       MH_ALIGN(m, sizeof(*ea));
+       ea = mtod(m, struct ether_arp *);
+       eh = (struct ether_header *)sa.sa_data;
+       bzero((caddr_t)ea, sizeof (*ea));
+       bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+           sizeof(eh->ether_dhost));
+       eh->ether_type = ETHERTYPE_ARP;         /* if_output will swap */
+       ea->arp_hrd = htons(ARPHRD_ETHER);
+       ea->arp_pro = htons(ETHERTYPE_IP);
+       ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
+       ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
+       ea->arp_op = htons(ARPOP_REQUEST);
+       bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
+          sizeof(ea->arp_sha));
+       bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
+          sizeof(ea->arp_spa));
+       bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
+       sa.sa_family = AF_UNSPEC;
+       sa.sa_len = sizeof(sa);
+       (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
+}
+
+int    useloopback = 1;        /* use loopback interface for local traffic */
+
+/*
+ * Resolve an IP address into an ethernet address.  If success, 
+ * desten is filled in.  If there is no entry in arptab,
+ * set one up and broadcast a request for the IP address.
+ * Hold onto this mbuf and resend it once the address
+ * is finally resolved.  A return value of 1 indicates
+ * that desten has been filled in and the packet should be sent
+ * normally; a 0 return indicates that the packet has been
+ * taken over here, either now or for later transmission.
+ *
+ * We do some (conservative) locking here at splimp, since
+ * arptab is also altered from input interrupt service (ecintr/ilintr
+ * calls arpinput when ETHERTYPE_ARP packets come in).
+ */
+arpresolve(ac, m, destip, desten, usetrailers)
+       register struct arpcom *ac;
+       struct mbuf *m;
+       register struct in_addr *destip;
+       register u_char *desten;
+       int *usetrailers;
+{
+       register struct arptab *at;
+       struct sockaddr_in sin;
+       register struct in_ifaddr *ia;
+       u_long lna;
+       int s;
+
+       *usetrailers = 0;
+       if (m->m_flags & M_BCAST) {     /* broadcast */
+               bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
+                   sizeof(etherbroadcastaddr));
+               return (1);
+       }
+       lna = in_lnaof(*destip);
+       /* if for us, use software loopback driver if up */
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+           if ((ia->ia_ifp == &ac->ac_if) &&
+               (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
+               /*
+                * This test used to be
+                *      if (loif.if_flags & IFF_UP)
+                * It allowed local traffic to be forced
+                * through the hardware by configuring the loopback down.
+                * However, it causes problems during network configuration
+                * for boards that can't receive packets they send.
+                * It is now necessary to clear "useloopback"
+                * to force traffic out to the hardware.
+                */
+               if (useloopback) {
+                       sin.sin_family = AF_INET;
+                       sin.sin_addr = *destip;
+                       (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
+                       /*
+                        * The packet has already been sent and freed.
+                        */
+                       return (0);
+               } else {
+                       bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
+                           sizeof(ac->ac_enaddr));
+                       return (1);
+               }
+       }
+       s = splimp();
+       ARPTAB_LOOK(at, destip->s_addr);
+       if (at == 0) {                  /* not found */
+               if (ac->ac_if.if_flags & IFF_NOARP) {
+                       bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
+                       desten[3] = (lna >> 16) & 0x7f;
+                       desten[4] = (lna >> 8) & 0xff;
+                       desten[5] = lna & 0xff;
+                       splx(s);
+                       return (1);
+               } else {
+                       at = arptnew(destip);
+                       if (at == 0)
+                               panic("arpresolve: no free entry");
+                       at->at_hold = m;
+                       arpwhohas(ac, destip);
+                       splx(s);
+                       return (0);
+               }
+       }
+       at->at_timer = 0;               /* restart the timer */
+       if (at->at_flags & ATF_COM) {   /* entry IS complete */
+               bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
+                   sizeof(at->at_enaddr));
+               if (at->at_flags & ATF_USETRAILERS)
+                       *usetrailers = 1;
+               splx(s);
+               return (1);
+       }
+       /*
+        * There is an arptab entry, but no ethernet address
+        * response yet.  Replace the held mbuf with this
+        * latest one.
+        */
+       if (at->at_hold)
+               m_freem(at->at_hold);
+       at->at_hold = m;
+       arpwhohas(ac, destip);          /* ask again */
+       splx(s);
+       return (0);
+}
+
+/*
+ * Called from 10 Mb/s Ethernet interrupt handlers
+ * when ether packet type ETHERTYPE_ARP
+ * is received.  Common length and type checks are done here,
+ * then the protocol-specific routine is called.
+ */
+arpinput(ac, m)
+       struct arpcom *ac;
+       struct mbuf *m;
+{
+       register struct arphdr *ar;
+
+       if (ac->ac_if.if_flags & IFF_NOARP)
+               goto out;
+       if (m->m_len < sizeof(struct arphdr))
+               goto out;
+       ar = mtod(m, struct arphdr *);
+       if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
+               goto out;
+       if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
+               goto out;
+
+       switch (ntohs(ar->ar_pro)) {
+
+       case ETHERTYPE_IP:
+       case ETHERTYPE_IPTRAILERS:
+               in_arpinput(ac, m);
+               return;
+
+       default:
+               break;
+       }
+out:
+       m_freem(m);
+}
+
+/*
+ * ARP for Internet protocols on 10 Mb/s Ethernet.
+ * Algorithm is that given in RFC 826.
+ * In addition, a sanity check is performed on the sender
+ * protocol address, to catch impersonators.
+ * We also handle negotiations for use of trailer protocol:
+ * ARP replies for protocol type ETHERTYPE_TRAIL are sent
+ * along with IP replies if we want trailers sent to us,
+ * and also send them in response to IP replies.
+ * This allows either end to announce the desire to receive
+ * trailer packets.
+ * We reply to requests for ETHERTYPE_TRAIL protocol as well,
+ * but don't normally send requests.
+ */
+in_arpinput(ac, m)
+       register struct arpcom *ac;
+       struct mbuf *m;
+{
+       register struct ether_arp *ea;
+       struct ether_header *eh;
+       register struct arptab *at;  /* same as "merge" flag */
+       register struct in_ifaddr *ia;
+       struct in_ifaddr *maybe_ia = 0;
+       struct mbuf *mcopy = 0;
+       struct sockaddr_in sin;
+       struct sockaddr sa;
+       struct in_addr isaddr, itaddr, myaddr;
+       int proto, op, s, completed = 0;
+
+       ea = mtod(m, struct ether_arp *);
+       proto = ntohs(ea->arp_pro);
+       op = ntohs(ea->arp_op);
+       bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
+       bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+               if (ia->ia_ifp == &ac->ac_if) {
+                       maybe_ia = ia;
+                       if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
+                            (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
+                               break;
+               }
+       if (maybe_ia == 0)
+               goto out;
+       myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
+       if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
+           sizeof (ea->arp_sha)))
+               goto out;       /* it's from me, ignore it. */
+       if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
+           sizeof (ea->arp_sha))) {
+               log(LOG_ERR,
+                   "arp: ether address is broadcast for IP address %x!\n",
+                   ntohl(isaddr.s_addr));
+               goto out;
+       }
+       if (isaddr.s_addr == myaddr.s_addr) {
+               log(LOG_ERR,
+                  "duplicate IP address %x!! sent from ethernet address: %s\n",
+                  ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
+               itaddr = myaddr;
+               if (op == ARPOP_REQUEST)
+                       goto reply;
+               goto out;
+       }
+       s = splimp();
+       ARPTAB_LOOK(at, isaddr.s_addr);
+       if (at) {
+               bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
+                   sizeof(ea->arp_sha));
+               if ((at->at_flags & ATF_COM) == 0)
+                       completed = 1;
+               at->at_flags |= ATF_COM;
+               if (at->at_hold) {
+                       sin.sin_family = AF_INET;
+                       sin.sin_addr = isaddr;
+                       (*ac->ac_if.if_output)(&ac->ac_if, at->at_hold,
+                               (struct sockaddr *)&sin, (struct rtentry *)0);
+                       at->at_hold = 0;
+               }
+       }
+       if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
+               /* ensure we have a table entry */
+               if (at = arptnew(&isaddr)) {
+                       bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
+                           sizeof(ea->arp_sha));
+                       completed = 1;
+                       at->at_flags |= ATF_COM;
+               }
+       }
+       splx(s);
+reply:
+       switch (proto) {
+
+       case ETHERTYPE_IPTRAILERS:
+               /* partner says trailers are OK */
+               if (at)
+                       at->at_flags |= ATF_USETRAILERS;
+               /*
+                * Reply to request iff we want trailers.
+                */
+               if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
+                       goto out;
+               break;
+
+       case ETHERTYPE_IP:
+               /*
+                * Reply if this is an IP request,
+                * or if we want to send a trailer response.
+                * Send the latter only to the IP response
+                * that completes the current ARP entry.
+                */
+               if (op != ARPOP_REQUEST &&
+                   (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
+                       goto out;
+       }
+       if (itaddr.s_addr == myaddr.s_addr) {
+               /* I am the target */
+               bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
+                   sizeof(ea->arp_sha));
+               bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
+                   sizeof(ea->arp_sha));
+       } else {
+               ARPTAB_LOOK(at, itaddr.s_addr);
+               if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
+                       goto out;
+               bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
+                   sizeof(ea->arp_sha));
+               bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
+                   sizeof(ea->arp_sha));
+       }
+
+       bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
+           sizeof(ea->arp_spa));
+       bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
+           sizeof(ea->arp_spa));
+       ea->arp_op = htons(ARPOP_REPLY); 
+       /*
+        * If incoming packet was an IP reply,
+        * we are sending a reply for type IPTRAILERS.
+        * If we are sending a reply for type IP
+        * and we want to receive trailers,
+        * send a trailer reply as well.
+        */
+       if (op == ARPOP_REPLY)
+               ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
+       else if (proto == ETHERTYPE_IP &&
+           (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
+               mcopy = m_copy(m, 0, (int)M_COPYALL);
+       eh = (struct ether_header *)sa.sa_data;
+       bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
+           sizeof(eh->ether_dhost));
+       eh->ether_type = ETHERTYPE_ARP;
+       sa.sa_family = AF_UNSPEC;
+       sa.sa_len = sizeof(sa);
+       (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
+       if (mcopy) {
+               ea = mtod(mcopy, struct ether_arp *);
+               ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
+               (*ac->ac_if.if_output)(&ac->ac_if,
+                                       mcopy, &sa, (struct rtentry *)0);
+       }
+       return;
+out:
+       m_freem(m);
+       return;
+}
+
+/*
+ * Free an arptab entry.
+ */
+arptfree(at)
+       register struct arptab *at;
+{
+       int s = splimp();
+
+       if (at->at_hold)
+               m_freem(at->at_hold);
+       at->at_hold = 0;
+       at->at_timer = at->at_flags = 0;
+       at->at_iaddr.s_addr = 0;
+       splx(s);
+}
+
+/*
+ * Enter a new address in arptab, pushing out the oldest entry 
+ * from the bucket if there is no room.
+ * This always succeeds since no bucket can be completely filled
+ * with permanent entries (except from arpioctl when testing whether
+ * another permanent entry will fit).
+ * MUST BE CALLED AT SPLIMP.
+ */
+struct arptab *
+arptnew(addr)
+       struct in_addr *addr;
+{
+       register n;
+       int oldest = -1;
+       register struct arptab *at, *ato = NULL;
+       static int first = 1;
+
+       if (first) {
+               first = 0;
+               timeout(arptimer, (caddr_t)0, hz);
+       }
+       at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
+       for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
+               if (at->at_flags == 0)
+                       goto out;        /* found an empty entry */
+               if (at->at_flags & ATF_PERM)
+                       continue;
+               if ((int) at->at_timer > oldest) {
+                       oldest = at->at_timer;
+                       ato = at;
+               }
+       }
+       if (ato == NULL)
+               return (NULL);
+       at = ato;
+       arptfree(at);
+out:
+       at->at_iaddr = *addr;
+       at->at_flags = ATF_INUSE;
+       return (at);
+}
+
+arpioctl(cmd, data)
+       int cmd;
+       caddr_t data;
+{
+       register struct arpreq *ar = (struct arpreq *)data;
+       register struct arptab *at;
+       register struct sockaddr_in *sin;
+       int s;
+
+       sin = (struct sockaddr_in *)&ar->arp_ha;
+#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
+       if (sin->sin_family == 0 && sin->sin_len < 16)
+               sin->sin_family = sin->sin_len;
+#endif
+       sin->sin_len = sizeof(ar->arp_ha);
+       sin = (struct sockaddr_in *)&ar->arp_pa;
+#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
+       if (sin->sin_family == 0 && sin->sin_len < 16)
+               sin->sin_family = sin->sin_len;
+#endif
+       sin->sin_len = sizeof(ar->arp_pa);
+       if (ar->arp_pa.sa_family != AF_INET ||
+           ar->arp_ha.sa_family != AF_UNSPEC)
+               return (EAFNOSUPPORT);
+       s = splimp();
+       ARPTAB_LOOK(at, sin->sin_addr.s_addr);
+       if (at == NULL) {               /* not found */
+               if (cmd != SIOCSARP) {
+                       splx(s);
+                       return (ENXIO);
+               }
+               if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
+                       splx(s);
+                       return (ENETUNREACH);
+               }
+       }
+       switch (cmd) {
+
+       case SIOCSARP:          /* set entry */
+               if (at == NULL) {
+                       at = arptnew(&sin->sin_addr);
+                       if (at == NULL) {
+                               splx(s);
+                               return (EADDRNOTAVAIL);
+                       }
+                       if (ar->arp_flags & ATF_PERM) {
+                       /* never make all entries in a bucket permanent */
+                               register struct arptab *tat;
+                               
+                               /* try to re-allocate */
+                               tat = arptnew(&sin->sin_addr);
+                               if (tat == NULL) {
+                                       arptfree(at);
+                                       splx(s);
+                                       return (EADDRNOTAVAIL);
+                               }
+                               arptfree(tat);
+                       }
+               }
+               bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
+                   sizeof(at->at_enaddr));
+               at->at_flags = ATF_COM | ATF_INUSE |
+                       (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
+               at->at_timer = 0;
+               break;
+
+       case SIOCDARP:          /* delete entry */
+               arptfree(at);
+               break;
+
+       case SIOCGARP:          /* get entry */
+       case OSIOCGARP:
+               bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
+                   sizeof(at->at_enaddr));
+#ifdef COMPAT_43
+               if (cmd == OSIOCGARP)
+                       *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family;
+#endif
+               ar->arp_flags = at->at_flags;
+               break;
+       }
+       splx(s);
+       return (0);
+}
diff --git a/usr/src/sys.386bsd/netinet/if_ether.h b/usr/src/sys.386bsd/netinet/if_ether.h
new file mode 100644 (file)
index 0000000..ef86f7c
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)if_ether.h  7.5 (Berkeley) 6/28/90
+ */
+
+/*
+ * Structure of a 10Mb/s Ethernet header.
+ */
+struct ether_header {
+       u_char  ether_dhost[6];
+       u_char  ether_shost[6];
+       u_short ether_type;
+};
+
+#define        ETHERTYPE_PUP   0x0200          /* PUP protocol */
+#define        ETHERTYPE_IP    0x0800          /* IP protocol */
+#define ETHERTYPE_ARP  0x0806          /* Addr. resolution protocol */
+
+/*
+ * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have
+ * (type-ETHERTYPE_TRAIL)*512 bytes of data followed
+ * by an ETHER type (as given above) and then the (variable-length) header.
+ */
+#define        ETHERTYPE_TRAIL         0x1000          /* Trailer packet */
+#define        ETHERTYPE_NTRAILER      16
+
+#define        ETHERMTU        1500
+#define        ETHERMIN        (60-14)
+
+/*
+ * Ethernet Address Resolution Protocol.
+ *
+ * See RFC 826 for protocol description.  Structure below is adapted
+ * to resolving internet addresses.  Field names used correspond to 
+ * RFC 826.
+ */
+struct ether_arp {
+       struct  arphdr ea_hdr;  /* fixed-size header */
+       u_char  arp_sha[6];     /* sender hardware address */
+       u_char  arp_spa[4];     /* sender protocol address */
+       u_char  arp_tha[6];     /* target hardware address */
+       u_char  arp_tpa[4];     /* target protocol address */
+};
+#define        arp_hrd ea_hdr.ar_hrd
+#define        arp_pro ea_hdr.ar_pro
+#define        arp_hln ea_hdr.ar_hln
+#define        arp_pln ea_hdr.ar_pln
+#define        arp_op  ea_hdr.ar_op
+
+
+/*
+ * Structure shared between the ethernet driver modules and
+ * the address resolution code.  For example, each ec_softc or il_softc
+ * begins with this structure.
+ */
+struct arpcom {
+       struct  ifnet ac_if;            /* network-visible interface */
+       u_char  ac_enaddr[6];           /* ethernet hardware address */
+       struct in_addr ac_ipaddr;       /* copy of ip address- XXX */
+};
+
+/*
+ * Internet to ethernet address resolution table.
+ */
+struct arptab {
+       struct  in_addr at_iaddr;       /* internet address */
+       u_char  at_enaddr[6];           /* ethernet address */
+       u_char  at_timer;               /* minutes since last reference */
+       u_char  at_flags;               /* flags */
+       struct  mbuf *at_hold;          /* last packet until resolved/timeout */
+};
+
+#ifdef KERNEL
+u_char etherbroadcastaddr[6];
+struct arptab *arptnew();
+int    ether_output(), ether_input();
+char   *ether_sprintf();
+#endif
diff --git a/usr/src/sys.386bsd/netinet/in.c b/usr/src/sys.386bsd/netinet/in.c
new file mode 100644 (file)
index 0000000..75824d1
--- /dev/null
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in.c        7.17 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "in_systm.h"
+#include "net/if.h"
+#include "net/route.h"
+#include "net/af.h"
+#include "in.h"
+#include "in_var.h"
+
+#ifdef INET
+/*
+ * Formulate an Internet address from network + host.
+ */
+struct in_addr
+in_makeaddr(net, host)
+       u_long net, host;
+{
+       register struct in_ifaddr *ia;
+       register u_long mask;
+       u_long addr;
+
+       if (IN_CLASSA(net))
+               mask = IN_CLASSA_HOST;
+       else if (IN_CLASSB(net))
+               mask = IN_CLASSB_HOST;
+       else
+               mask = IN_CLASSC_HOST;
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+               if ((ia->ia_netmask & net) == ia->ia_net) {
+                       mask = ~ia->ia_subnetmask;
+                       break;
+               }
+       addr = htonl(net | (host & mask));
+       return (*(struct in_addr *)&addr);
+}
+
+/*
+ * Return the network number from an internet address.
+ */
+u_long
+in_netof(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+       register u_long net;
+       register struct in_ifaddr *ia;
+
+       if (IN_CLASSA(i))
+               net = i & IN_CLASSA_NET;
+       else if (IN_CLASSB(i))
+               net = i & IN_CLASSB_NET;
+       else if (IN_CLASSC(i))
+               net = i & IN_CLASSC_NET;
+       else
+               return (0);
+
+       /*
+        * Check whether network is a subnet;
+        * if so, return subnet number.
+        */
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+               if (net == ia->ia_net)
+                       return (i & ia->ia_subnetmask);
+       return (net);
+}
+
+/*
+ * Compute and save network mask as sockaddr from an internet address.
+ */
+in_sockmaskof(in, sockmask)
+       struct in_addr in;
+       register struct sockaddr_in *sockmask;
+{
+       register u_long net;
+       register u_long mask;
+    {
+       register u_long i = ntohl(in.s_addr);
+
+       if (i == 0)
+               net = 0, mask = 0;
+       else if (IN_CLASSA(i))
+               net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
+       else if (IN_CLASSB(i))
+               net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
+       else if (IN_CLASSC(i))
+               net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
+       else
+               net = i, mask = -1;
+    }
+    {
+       register struct in_ifaddr *ia;
+       /*
+        * Check whether network is a subnet;
+        * if so, return subnet number.
+        */
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+               if (net == ia->ia_net)
+                       mask =  ia->ia_subnetmask;
+    }
+    {
+       register char *cpbase = (char *)&(sockmask->sin_addr);
+       register char *cp = (char *)(1 + &(sockmask->sin_addr));
+
+       sockmask->sin_addr.s_addr = htonl(mask);
+       sockmask->sin_len = 0;
+       while (--cp >= cpbase)
+               if (*cp) {
+                       sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
+                       break;
+               }
+    }
+}
+
+/*
+ * Return the host portion of an internet address.
+ */
+u_long
+in_lnaof(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+       register u_long net, host;
+       register struct in_ifaddr *ia;
+
+       if (IN_CLASSA(i)) {
+               net = i & IN_CLASSA_NET;
+               host = i & IN_CLASSA_HOST;
+       } else if (IN_CLASSB(i)) {
+               net = i & IN_CLASSB_NET;
+               host = i & IN_CLASSB_HOST;
+       } else if (IN_CLASSC(i)) {
+               net = i & IN_CLASSC_NET;
+               host = i & IN_CLASSC_HOST;
+       } else
+               return (i);
+
+       /*
+        * Check whether network is a subnet;
+        * if so, use the modified interpretation of `host'.
+        */
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+               if (net == ia->ia_net)
+                       return (host &~ ia->ia_subnetmask);
+       return (host);
+}
+
+#ifndef SUBNETSARELOCAL
+#define        SUBNETSARELOCAL 1
+#endif
+int subnetsarelocal = SUBNETSARELOCAL;
+/*
+ * Return 1 if an internet address is for a ``local'' host
+ * (one to which we have a connection).  If subnetsarelocal
+ * is true, this includes other subnets of the local net.
+ * Otherwise, it includes only the directly-connected (sub)nets.
+ */
+in_localaddr(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+       register struct in_ifaddr *ia;
+
+       if (subnetsarelocal) {
+               for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                       if ((i & ia->ia_netmask) == ia->ia_net)
+                               return (1);
+       } else {
+               for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                       if ((i & ia->ia_subnetmask) == ia->ia_subnet)
+                               return (1);
+       }
+       return (0);
+}
+
+/*
+ * Determine whether an IP address is in a reserved set of addresses
+ * that may not be forwarded, or whether datagrams to that destination
+ * may be forwarded.
+ */
+in_canforward(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+       register u_long net;
+
+       if (IN_EXPERIMENTAL(i))
+               return (0);
+       if (IN_CLASSA(i)) {
+               net = i & IN_CLASSA_NET;
+               if (net == 0 || net == IN_LOOPBACKNET)
+                       return (0);
+       }
+       return (1);
+}
+
+int    in_interfaces;          /* number of external internet interfaces */
+extern struct ifnet loif;
+
+/*
+ * Generic internet control operations (ioctl's).
+ * Ifp is 0 if not an interface-specific ioctl.
+ */
+/* ARGSUSED */
+in_control(so, cmd, data, ifp)
+       struct socket *so;
+       int cmd;
+       caddr_t data;
+       register struct ifnet *ifp;
+{
+       register struct ifreq *ifr = (struct ifreq *)data;
+       register struct in_ifaddr *ia = 0;
+       register struct ifaddr *ifa;
+       struct in_ifaddr *oia;
+       struct in_aliasreq *ifra = (struct in_aliasreq *)data;
+       struct mbuf *m;
+       struct sockaddr_in oldaddr;
+       int error, hostIsNew, maskIsNew;
+       u_long i;
+
+       /*
+        * Find address for this interface, if it exists.
+        */
+       if (ifp)
+               for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                       if (ia->ia_ifp == ifp)
+                               break;
+
+       switch (cmd) {
+
+       case SIOCAIFADDR:
+       case SIOCDIFADDR:
+               if (ifra->ifra_addr.sin_family == AF_INET)
+                   for (oia = ia; ia; ia = ia->ia_next) {
+                       if (ia->ia_ifp == ifp  &&
+                           ia->ia_addr.sin_addr.s_addr ==
+                               ifra->ifra_addr.sin_addr.s_addr)
+                           break;
+               }
+               if (cmd == SIOCDIFADDR && ia == 0)
+                       return (EADDRNOTAVAIL);
+               /* FALLTHROUGH */
+       case SIOCSIFADDR:
+       case SIOCSIFNETMASK:
+       case SIOCSIFDSTADDR:
+               if ((so->so_state & SS_PRIV) == 0)
+                       return (EPERM);
+
+               if (ifp == 0)
+                       panic("in_control");
+               if (ia == (struct in_ifaddr *)0) {
+                       m = m_getclr(M_WAIT, MT_IFADDR);
+                       if (m == (struct mbuf *)NULL)
+                               return (ENOBUFS);
+                       if (ia = in_ifaddr) {
+                               for ( ; ia->ia_next; ia = ia->ia_next)
+                                       ;
+                               ia->ia_next = mtod(m, struct in_ifaddr *);
+                       } else
+                               in_ifaddr = mtod(m, struct in_ifaddr *);
+                       ia = mtod(m, struct in_ifaddr *);
+                       if (ifa = ifp->if_addrlist) {
+                               for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
+                                       ;
+                               ifa->ifa_next = (struct ifaddr *) ia;
+                       } else
+                               ifp->if_addrlist = (struct ifaddr *) ia;
+                       ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+                       ia->ia_ifa.ifa_dstaddr
+                                       = (struct sockaddr *)&ia->ia_dstaddr;
+                       ia->ia_ifa.ifa_netmask
+                                       = (struct sockaddr *)&ia->ia_sockmask;
+                       ia->ia_sockmask.sin_len = 8;
+                       if (ifp->if_flags & IFF_BROADCAST) {
+                               ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
+                               ia->ia_broadaddr.sin_family = AF_INET;
+                       }
+                       ia->ia_ifp = ifp;
+                       if (ifp != &loif)
+                               in_interfaces++;
+               }
+               break;
+
+       case SIOCSIFBRDADDR:
+               if ((so->so_state & SS_PRIV) == 0)
+                       return (EPERM);
+               /* FALLTHROUGH */
+
+       case SIOCGIFADDR:
+       case SIOCGIFNETMASK:
+       case SIOCGIFDSTADDR:
+       case SIOCGIFBRDADDR:
+               if (ia == (struct in_ifaddr *)0)
+                       return (EADDRNOTAVAIL);
+               break;
+
+       default:
+               return (EOPNOTSUPP);
+               break;
+       }
+       switch (cmd) {
+
+       case SIOCGIFADDR:
+               *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
+               break;
+
+       case SIOCGIFBRDADDR:
+               if ((ifp->if_flags & IFF_BROADCAST) == 0)
+                       return (EINVAL);
+               *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
+               break;
+
+       case SIOCGIFDSTADDR:
+               if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+                       return (EINVAL);
+               *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
+               break;
+
+       case SIOCGIFNETMASK:
+               *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
+               break;
+
+       case SIOCSIFDSTADDR:
+               if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+                       return (EINVAL);
+               oldaddr = ia->ia_dstaddr;
+               ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
+               if (ifp->if_ioctl &&
+                   (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
+                       ia->ia_dstaddr = oldaddr;
+                       return (error);
+               }
+               if (ia->ia_flags & IFA_ROUTE) {
+                       ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
+                       rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+                       ia->ia_ifa.ifa_dstaddr =
+                                       (struct sockaddr *)&ia->ia_dstaddr;
+                       rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
+               }
+               break;
+
+       case SIOCSIFBRDADDR:
+               if ((ifp->if_flags & IFF_BROADCAST) == 0)
+                       return (EINVAL);
+               ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
+               break;
+
+       case SIOCSIFADDR:
+               return (in_ifinit(ifp, ia,
+                   (struct sockaddr_in *) &ifr->ifr_addr, 1));
+
+       case SIOCSIFNETMASK:
+               i = ifra->ifra_addr.sin_addr.s_addr;
+               ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
+               break;
+
+       case SIOCAIFADDR:
+               maskIsNew = 0;
+               hostIsNew = 1;
+               error = 0;
+               if (ia->ia_addr.sin_family == AF_INET) {
+                       if (ifra->ifra_addr.sin_len == 0) {
+                               ifra->ifra_addr = ia->ia_addr;
+                               hostIsNew = 0;
+                       } else if (ifra->ifra_addr.sin_addr.s_addr ==
+                                              ia->ia_addr.sin_addr.s_addr)
+                               hostIsNew = 0;
+               }
+               if (ifra->ifra_mask.sin_len) {
+                       in_ifscrub(ifp, ia);
+                       ia->ia_sockmask = ifra->ifra_mask;
+                       ia->ia_subnetmask =
+                            ntohl(ia->ia_sockmask.sin_addr.s_addr);
+                       maskIsNew = 1;
+               }
+               if ((ifp->if_flags & IFF_POINTOPOINT) &&
+                   (ifra->ifra_dstaddr.sin_family == AF_INET)) {
+                       in_ifscrub(ifp, ia);
+                       ia->ia_dstaddr = ifra->ifra_dstaddr;
+                       maskIsNew  = 1; /* We lie; but the effect's the same */
+               }
+               if (ifra->ifra_addr.sin_family == AF_INET &&
+                   (hostIsNew || maskIsNew))
+                       error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
+               if ((ifp->if_flags & IFF_BROADCAST) &&
+                   (ifra->ifra_broadaddr.sin_family == AF_INET))
+                       ia->ia_broadaddr = ifra->ifra_broadaddr;
+               return (error);
+
+       case SIOCDIFADDR:
+               in_ifscrub(ifp, ia);
+               if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
+                       ifp->if_addrlist = ifa->ifa_next;
+               else {
+                       while (ifa->ifa_next &&
+                              (ifa->ifa_next != (struct ifaddr *)ia))
+                                   ifa = ifa->ifa_next;
+                       if (ifa->ifa_next)
+                               ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
+                       else
+                               printf("Couldn't unlink inifaddr from ifp\n");
+               }
+               oia = ia;
+               if (oia == (ia = in_ifaddr))
+                       in_ifaddr = ia->ia_next;
+               else {
+                       while (ia->ia_next && (ia->ia_next != oia))
+                               ia = ia->ia_next;
+                       if (ia->ia_next)
+                               ia->ia_next = oia->ia_next;
+                       else
+                               printf("Didn't unlink inifadr from list\n");
+               }
+               (void) m_free(dtom(oia));
+               break;
+
+       default:
+               if (ifp == 0 || ifp->if_ioctl == 0)
+                       return (EOPNOTSUPP);
+               return ((*ifp->if_ioctl)(ifp, cmd, data));
+       }
+       return (0);
+}
+
+/*
+ * Delete any existing route for an interface.
+ */
+in_ifscrub(ifp, ia)
+       register struct ifnet *ifp;
+       register struct in_ifaddr *ia;
+{
+
+       if ((ia->ia_flags & IFA_ROUTE) == 0)
+               return;
+       if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
+               rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+       else
+               rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
+       ia->ia_flags &= ~IFA_ROUTE;
+}
+
+/*
+ * Initialize an interface's internet address
+ * and routing table entry.
+ */
+in_ifinit(ifp, ia, sin, scrub)
+       register struct ifnet *ifp;
+       register struct in_ifaddr *ia;
+       struct sockaddr_in *sin;
+{
+       register u_long i = ntohl(sin->sin_addr.s_addr);
+       struct sockaddr_in oldaddr;
+       int s = splimp(), error, flags = RTF_UP;
+
+       oldaddr = ia->ia_addr;
+       ia->ia_addr = *sin;
+       /*
+        * Give the interface a chance to initialize
+        * if this is its first address,
+        * and to validate the address if necessary.
+        */
+       if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
+               splx(s);
+               ia->ia_addr = oldaddr;
+               return (error);
+       }
+       splx(s);
+       if (scrub) {
+               ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
+               in_ifscrub(ifp, ia);
+               ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+       }
+       if (IN_CLASSA(i))
+               ia->ia_netmask = IN_CLASSA_NET;
+       else if (IN_CLASSB(i))
+               ia->ia_netmask = IN_CLASSB_NET;
+       else
+               ia->ia_netmask = IN_CLASSC_NET;
+       ia->ia_net = i & ia->ia_netmask;
+       /*
+        * The subnet mask includes at least the standard network part,
+        * but may already have been set to a larger value.
+        */
+       ia->ia_subnetmask |= ia->ia_netmask;
+       ia->ia_subnet = i & ia->ia_subnetmask;
+       ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
+       {
+               register char *cp = (char *) (1 + &(ia->ia_sockmask.sin_addr));
+               register char *cpbase = (char *) &(ia->ia_sockmask.sin_addr);
+               while (--cp >= cpbase)
+                       if (*cp) {
+                               ia->ia_sockmask.sin_len =
+                                       1 + cp - (char *) &(ia->ia_sockmask);
+                               break;
+                       }
+       }
+       /*
+        * Add route for the network.
+        */
+       if (ifp->if_flags & IFF_BROADCAST) {
+               ia->ia_broadaddr.sin_addr = 
+                       in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
+               ia->ia_netbroadcast.s_addr =
+                   htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
+       } else if (ifp->if_flags & IFF_LOOPBACK) {
+               ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
+               flags |= RTF_HOST;
+       } else if (ifp->if_flags & IFF_POINTOPOINT) {
+               if (ia->ia_dstaddr.sin_family != AF_INET)
+                       return (0);
+               flags |= RTF_HOST;
+       }
+       if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
+               ia->ia_flags |= IFA_ROUTE;
+       return (error);
+}
+
+/*
+ * Return address info for specified internet network.
+ */
+struct in_ifaddr *
+in_iaonnetof(net)
+       u_long net;
+{
+       register struct in_ifaddr *ia;
+
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+               if (ia->ia_subnet == net)
+                       return (ia);
+       return ((struct in_ifaddr *)0);
+}
+
+/*
+ * Return 1 if the address might be a local broadcast address.
+ */
+in_broadcast(in)
+       struct in_addr in;
+{
+       register struct in_ifaddr *ia;
+       u_long t;
+
+       /*
+        * Look through the list of addresses for a match
+        * with a broadcast address.
+        */
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+           if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
+               if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
+                    return (1);
+               /*
+                * Check for old-style (host 0) broadcast.
+                */
+               if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
+                   return (1);
+       }
+       if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
+               return (1);
+       return (0);
+}
+#endif
diff --git a/usr/src/sys.386bsd/netinet/in.h b/usr/src/sys.386bsd/netinet/in.h
new file mode 100644 (file)
index 0000000..be63cbf
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in.h        7.11 (Berkeley) 4/20/91
+ */
+
+/*
+ * Constants and structures defined by the internet system,
+ * Per RFC 790, September 1981.
+ */
+
+/*
+ * Protocols
+ */
+#define        IPPROTO_IP              0               /* dummy for IP */
+#define        IPPROTO_ICMP            1               /* control message protocol */
+#define        IPPROTO_GGP             3               /* gateway^2 (deprecated) */
+#define        IPPROTO_TCP             6               /* tcp */
+#define        IPPROTO_EGP             8               /* exterior gateway protocol */
+#define        IPPROTO_PUP             12              /* pup */
+#define        IPPROTO_UDP             17              /* user datagram protocol */
+#define        IPPROTO_IDP             22              /* xns idp */
+#define        IPPROTO_TP              29              /* tp-4 w/ class negotiation */
+#define        IPPROTO_EON             80              /* ISO cnlp */
+
+#define        IPPROTO_RAW             255             /* raw IP packet */
+#define        IPPROTO_MAX             256
+
+
+/*
+ * Local port number conventions:
+ * Ports < IPPORT_RESERVED are reserved for
+ * privileged processes (e.g. root).
+ * Ports > IPPORT_USERRESERVED are reserved
+ * for servers, not necessarily privileged.
+ */
+#define        IPPORT_RESERVED         1024
+#define        IPPORT_USERRESERVED     5000
+
+/*
+ * Internet address (a structure for historical reasons)
+ */
+struct in_addr {
+       u_long s_addr;
+};
+
+/*
+ * Definitions of bits in internet address integers.
+ * On subnets, the decomposition of addresses to host and net parts
+ * is done according to subnet mask, not the masks here.
+ */
+#define        IN_CLASSA(i)            (((long)(i) & 0x80000000) == 0)
+#define        IN_CLASSA_NET           0xff000000
+#define        IN_CLASSA_NSHIFT        24
+#define        IN_CLASSA_HOST          0x00ffffff
+#define        IN_CLASSA_MAX           128
+
+#define        IN_CLASSB(i)            (((long)(i) & 0xc0000000) == 0x80000000)
+#define        IN_CLASSB_NET           0xffff0000
+#define        IN_CLASSB_NSHIFT        16
+#define        IN_CLASSB_HOST          0x0000ffff
+#define        IN_CLASSB_MAX           65536
+
+#define        IN_CLASSC(i)            (((long)(i) & 0xe0000000) == 0xc0000000)
+#define        IN_CLASSC_NET           0xffffff00
+#define        IN_CLASSC_NSHIFT        8
+#define        IN_CLASSC_HOST          0x000000ff
+
+#define        IN_CLASSD(i)            (((long)(i) & 0xf0000000) == 0xe0000000)
+#define        IN_MULTICAST(i)         IN_CLASSD(i)
+
+#define        IN_EXPERIMENTAL(i)      (((long)(i) & 0xe0000000) == 0xe0000000)
+#define        IN_BADCLASS(i)          (((long)(i) & 0xf0000000) == 0xf0000000)
+
+#define        INADDR_ANY              (u_long)0x00000000
+#define        INADDR_BROADCAST        (u_long)0xffffffff      /* must be masked */
+#ifndef KERNEL
+#define        INADDR_NONE             0xffffffff              /* -1 return */
+#endif
+
+#define        IN_LOOPBACKNET          127                     /* official! */
+
+/*
+ * Socket address, internet style.
+ */
+struct sockaddr_in {
+       u_char  sin_len;
+       u_char  sin_family;
+       u_short sin_port;
+       struct  in_addr sin_addr;
+       char    sin_zero[8];
+};
+
+/*
+ * Structure used to describe IP options.
+ * Used to store options internally, to pass them to a process,
+ * or to restore options retrieved earlier.
+ * The ip_dst is used for the first-hop gateway when using a source route
+ * (this gets put into the header proper).
+ */
+struct ip_opts {
+       struct  in_addr ip_dst;         /* first hop, 0 w/o src rt */
+       char    ip_opts[40];            /* actually variable in size */
+};
+
+/*
+ * Options for use with [gs]etsockopt at the IP level.
+ * First word of comment is data type; bool is stored in int.
+ */
+#define        IP_OPTIONS      1       /* buf/ip_opts; set/get IP per-packet options */
+#define        IP_HDRINCL      2       /* int; header is included with data (raw) */
+#define        IP_TOS          3       /* int; IP type of service and precedence */
+#define        IP_TTL          4       /* int; IP time to live */
+#define        IP_RECVOPTS     5       /* bool; receive all IP options w/datagram */
+#define        IP_RECVRETOPTS  6       /* bool; receive IP options for response */
+#define        IP_RECVDSTADDR  7       /* bool; receive IP dst addr w/datagram */
+#define        IP_RETOPTS      8       /* ip_opts; set/get IP per-packet options */
+
+#ifdef KERNEL
+struct in_addr in_makeaddr();
+u_long in_netof(), in_lnaof();
+#endif
diff --git a/usr/src/sys.386bsd/netinet/in_cksum.c b/usr/src/sys.386bsd/netinet/in_cksum.c
new file mode 100644 (file)
index 0000000..68c9a54
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in_cksum.c  7.3 (Berkeley) 6/28/90
+ */
+
+#include "../h/types.h"
+#include "../h/mbuf.h"
+
+/*
+ * Checksum routine for Internet Protocol family headers (Portable Version).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ */
+
+#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
+#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
+
+in_cksum_c(m, len)
+       register struct mbuf *m;
+       register int len;
+{
+       register u_short *w;
+       register int sum = 0;
+       register int mlen = 0;
+       int byte_swapped = 0;
+
+       union {
+               char    c[2];
+               u_short s;
+       } s_util;
+       union {
+               u_short s[2];
+               long    l;
+       } l_util;
+
+       for (;m && len; m = m->m_next) {
+               if (m->m_len == 0)
+                       continue;
+               w = mtod(m, u_short *);
+               if (mlen == -1) {
+                       /*
+                        * The first byte of this mbuf is the continuation
+                        * of a word spanning between this mbuf and the
+                        * last mbuf.
+                        *
+                        * s_util.c[0] is already saved when scanning previous 
+                        * mbuf.
+                        */
+                       s_util.c[1] = *(char *)w;
+                       sum += s_util.s;
+                       w = (u_short *)((char *)w + 1);
+                       mlen = m->m_len - 1;
+                       len--;
+               } else
+                       mlen = m->m_len;
+               if (len < mlen)
+                       mlen = len;
+               len -= mlen;
+               /*
+                * Force to even boundary.
+                */
+               if ((1 & (int) w) && (mlen > 0)) {
+                       REDUCE;
+                       sum <<= 8;
+                       s_util.c[0] = *(u_char *)w;
+                       w = (u_short *)((char *)w + 1);
+                       mlen--;
+                       byte_swapped = 1;
+               }
+               /*
+                * Unroll the loop to make overhead from
+                * branches &c small.
+                */
+               while ((mlen -= 32) >= 0) {
+                       sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+                       sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+                       sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
+                       sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
+                       w += 16;
+               }
+               mlen += 32;
+               while ((mlen -= 8) >= 0) {
+                       sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+                       w += 4;
+               }
+               mlen += 8;
+               if (mlen == 0 && byte_swapped == 0)
+                       continue;
+               REDUCE;
+               while ((mlen -= 2) >= 0) {
+                       sum += *w++;
+               }
+               if (byte_swapped) {
+                       REDUCE;
+                       sum <<= 8;
+                       byte_swapped = 0;
+                       if (mlen == -1) {
+                               s_util.c[1] = *(char *)w;
+                               sum += s_util.s;
+                               mlen = 0;
+                       } else
+                               mlen = -1;
+               } else if (mlen == -1)
+                       s_util.c[0] = *(char *)w;
+       }
+       if (len)
+               printf("cksum: out of data\n");
+       if (mlen == -1) {
+               /* The last mbuf has odd # of bytes. Follow the
+                  standard (the odd byte may be shifted left by 8 bits
+                  or not as determined by endian-ness of the machine) */
+               s_util.c[1] = 0;
+               sum += s_util.s;
+       }
+       REDUCE;
+       return (~sum & 0xffff);
+}
diff --git a/usr/src/sys.386bsd/netinet/in_pcb.c b/usr/src/sys.386bsd/netinet/in_pcb.c
new file mode 100644 (file)
index 0000000..8b1c06e
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in_pcb.c    7.14 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "ioctl.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "in_var.h"
+
+struct in_addr zeroin_addr;
+
+in_pcballoc(so, head)
+       struct socket *so;
+       struct inpcb *head;
+{
+       struct mbuf *m;
+       register struct inpcb *inp;
+
+       m = m_getclr(M_DONTWAIT, MT_PCB);
+       if (m == NULL)
+               return (ENOBUFS);
+       inp = mtod(m, struct inpcb *);
+       inp->inp_head = head;
+       inp->inp_socket = so;
+       insque(inp, head);
+       so->so_pcb = (caddr_t)inp;
+       return (0);
+}
+       
+in_pcbbind(inp, nam)
+       register struct inpcb *inp;
+       struct mbuf *nam;
+{
+       register struct socket *so = inp->inp_socket;
+       register struct inpcb *head = inp->inp_head;
+       register struct sockaddr_in *sin;
+       u_short lport = 0;
+
+       if (in_ifaddr == 0)
+               return (EADDRNOTAVAIL);
+       if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
+               return (EINVAL);
+       if (nam == 0)
+               goto noname;
+       sin = mtod(nam, struct sockaddr_in *);
+       if (nam->m_len != sizeof (*sin))
+               return (EINVAL);
+       if (sin->sin_addr.s_addr != INADDR_ANY) {
+               int tport = sin->sin_port;
+
+               sin->sin_port = 0;              /* yech... */
+               if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
+                       return (EADDRNOTAVAIL);
+               sin->sin_port = tport;
+       }
+       lport = sin->sin_port;
+       if (lport) {
+               u_short aport = ntohs(lport);
+               int wild = 0;
+
+               /* GROSS */
+               if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
+                       return (EACCES);
+               /* even GROSSER, but this is the Internet */
+               if ((so->so_options & SO_REUSEADDR) == 0 &&
+                   ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
+                    (so->so_options & SO_ACCEPTCONN) == 0))
+                       wild = INPLOOKUP_WILDCARD;
+               if (in_pcblookup(head,
+                   zeroin_addr, 0, sin->sin_addr, lport, wild))
+                       return (EADDRINUSE);
+       }
+       inp->inp_laddr = sin->sin_addr;
+noname:
+       if (lport == 0)
+               do {
+                       if (head->inp_lport++ < IPPORT_RESERVED ||
+                           head->inp_lport > IPPORT_USERRESERVED)
+                               head->inp_lport = IPPORT_RESERVED;
+                       lport = htons(head->inp_lport);
+               } while (in_pcblookup(head,
+                           zeroin_addr, 0, inp->inp_laddr, lport, 0));
+       inp->inp_lport = lport;
+       return (0);
+}
+
+/*
+ * Connect from a socket to a specified address.
+ * Both address and port must be specified in argument sin.
+ * If don't have a local address for this socket yet,
+ * then pick one.
+ */
+in_pcbconnect(inp, nam)
+       register struct inpcb *inp;
+       struct mbuf *nam;
+{
+       struct in_ifaddr *ia;
+       struct sockaddr_in *ifaddr;
+       register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+
+       if (nam->m_len != sizeof (*sin))
+               return (EINVAL);
+       if (sin->sin_family != AF_INET)
+               return (EAFNOSUPPORT);
+       if (sin->sin_port == 0)
+               return (EADDRNOTAVAIL);
+       if (in_ifaddr) {
+               /*
+                * If the destination address is INADDR_ANY,
+                * use the primary local address.
+                * If the supplied address is INADDR_BROADCAST,
+                * and the primary interface supports broadcast,
+                * choose the broadcast address for that interface.
+                */
+#define        satosin(sa)     ((struct sockaddr_in *)(sa))
+               if (sin->sin_addr.s_addr == INADDR_ANY)
+                   sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
+               else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
+                 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
+                   sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
+       }
+       if (inp->inp_laddr.s_addr == INADDR_ANY) {
+               register struct route *ro;
+               struct ifnet *ifp;
+
+               ia = (struct in_ifaddr *)0;
+               /* 
+                * If route is known or can be allocated now,
+                * our src addr is taken from the i/f, else punt.
+                */
+               ro = &inp->inp_route;
+               if (ro->ro_rt &&
+                   (satosin(&ro->ro_dst)->sin_addr.s_addr !=
+                       sin->sin_addr.s_addr || 
+                   inp->inp_socket->so_options & SO_DONTROUTE)) {
+                       RTFREE(ro->ro_rt);
+                       ro->ro_rt = (struct rtentry *)0;
+               }
+               if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
+                   (ro->ro_rt == (struct rtentry *)0 ||
+                   ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
+                       /* No route yet, so try to acquire one */
+                       ro->ro_dst.sa_family = AF_INET;
+                       ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
+                       ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
+                               sin->sin_addr;
+                       rtalloc(ro);
+               }
+               /*
+                * If we found a route, use the address
+                * corresponding to the outgoing interface
+                * unless it is the loopback (in case a route
+                * to our address on another net goes to loopback).
+                */
+               if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
+                   (ifp->if_flags & IFF_LOOPBACK) == 0)
+                       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                               if (ia->ia_ifp == ifp)
+                                       break;
+               if (ia == 0) {
+                       int fport = sin->sin_port;
+
+                       sin->sin_port = 0;
+                       ia = (struct in_ifaddr *)
+                           ifa_ifwithdstaddr((struct sockaddr *)sin);
+                       sin->sin_port = fport;
+                       if (ia == 0)
+                               ia = in_iaonnetof(in_netof(sin->sin_addr));
+                       if (ia == 0)
+                               ia = in_ifaddr;
+                       if (ia == 0)
+                               return (EADDRNOTAVAIL);
+               }
+               ifaddr = (struct sockaddr_in *)&ia->ia_addr;
+       }
+       if (in_pcblookup(inp->inp_head,
+           sin->sin_addr,
+           sin->sin_port,
+           inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
+           inp->inp_lport,
+           0))
+               return (EADDRINUSE);
+       if (inp->inp_laddr.s_addr == INADDR_ANY) {
+               if (inp->inp_lport == 0)
+                       (void)in_pcbbind(inp, (struct mbuf *)0);
+               inp->inp_laddr = ifaddr->sin_addr;
+       }
+       inp->inp_faddr = sin->sin_addr;
+       inp->inp_fport = sin->sin_port;
+       return (0);
+}
+
+in_pcbdisconnect(inp)
+       struct inpcb *inp;
+{
+
+       inp->inp_faddr.s_addr = INADDR_ANY;
+       inp->inp_fport = 0;
+       if (inp->inp_socket->so_state & SS_NOFDREF)
+               in_pcbdetach(inp);
+}
+
+in_pcbdetach(inp)
+       struct inpcb *inp;
+{
+       struct socket *so = inp->inp_socket;
+
+       so->so_pcb = 0;
+       sofree(so);
+       if (inp->inp_options)
+               (void)m_free(inp->inp_options);
+       if (inp->inp_route.ro_rt)
+               rtfree(inp->inp_route.ro_rt);
+       remque(inp);
+       (void) m_free(dtom(inp));
+}
+
+in_setsockaddr(inp, nam)
+       register struct inpcb *inp;
+       struct mbuf *nam;
+{
+       register struct sockaddr_in *sin;
+       
+       nam->m_len = sizeof (*sin);
+       sin = mtod(nam, struct sockaddr_in *);
+       bzero((caddr_t)sin, sizeof (*sin));
+       sin->sin_family = AF_INET;
+       sin->sin_len = sizeof(*sin);
+       sin->sin_port = inp->inp_lport;
+       sin->sin_addr = inp->inp_laddr;
+}
+
+in_setpeeraddr(inp, nam)
+       struct inpcb *inp;
+       struct mbuf *nam;
+{
+       register struct sockaddr_in *sin;
+       
+       nam->m_len = sizeof (*sin);
+       sin = mtod(nam, struct sockaddr_in *);
+       bzero((caddr_t)sin, sizeof (*sin));
+       sin->sin_family = AF_INET;
+       sin->sin_len = sizeof(*sin);
+       sin->sin_port = inp->inp_fport;
+       sin->sin_addr = inp->inp_faddr;
+}
+
+/*
+ * Pass some notification to all connections of a protocol
+ * associated with address dst.  The local address and/or port numbers
+ * may be specified to limit the search.  The "usual action" will be
+ * taken, depending on the ctlinput cmd.  The caller must filter any
+ * cmds that are uninteresting (e.g., no error in the map).
+ * Call the protocol specific routine (if any) to report
+ * any errors for each matching socket.
+ *
+ * Must be called at splnet.
+ */
+in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
+       struct inpcb *head;
+       struct sockaddr *dst;
+       u_short fport, lport;
+       struct in_addr laddr;
+       int cmd, (*notify)();
+{
+       register struct inpcb *inp, *oinp;
+       struct in_addr faddr;
+       int errno;
+       int in_rtchange();
+       extern u_char inetctlerrmap[];
+
+       if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
+               return;
+       faddr = ((struct sockaddr_in *)dst)->sin_addr;
+       if (faddr.s_addr == INADDR_ANY)
+               return;
+
+       /*
+        * Redirects go to all references to the destination,
+        * and use in_rtchange to invalidate the route cache.
+        * Dead host indications: notify all references to the destination.
+        * Otherwise, if we have knowledge of the local port and address,
+        * deliver only to that socket.
+        */
+       if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
+               fport = 0;
+               lport = 0;
+               laddr.s_addr = 0;
+               if (cmd != PRC_HOSTDEAD)
+                       notify = in_rtchange;
+       }
+       errno = inetctlerrmap[cmd];
+       for (inp = head->inp_next; inp != head;) {
+               if (inp->inp_faddr.s_addr != faddr.s_addr ||
+                   inp->inp_socket == 0 ||
+                   (lport && inp->inp_lport != lport) ||
+                   (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
+                   (fport && inp->inp_fport != fport)) {
+                       inp = inp->inp_next;
+                       continue;
+               }
+               oinp = inp;
+               inp = inp->inp_next;
+               if (notify)
+                       (*notify)(oinp, errno);
+       }
+}
+
+/*
+ * Check for alternatives when higher level complains
+ * about service problems.  For now, invalidate cached
+ * routing information.  If the route was created dynamically
+ * (by a redirect), time to try a default gateway again.
+ */
+in_losing(inp)
+       struct inpcb *inp;
+{
+       register struct rtentry *rt;
+
+       if ((rt = inp->inp_route.ro_rt)) {
+               rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
+                           rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
+                           (struct sockaddr *)0, rt->rt_flags, 0);
+               if (rt->rt_flags & RTF_DYNAMIC)
+                       (void) rtrequest(RTM_DELETE, rt_key(rt),
+                               rt->rt_gateway, rt_mask(rt), rt->rt_flags, 
+                               (struct rtentry **)0);
+               inp->inp_route.ro_rt = 0;
+               rtfree(rt);
+               /*
+                * A new route can be allocated
+                * the next time output is attempted.
+                */
+       }
+}
+
+/*
+ * After a routing change, flush old routing
+ * and allocate a (hopefully) better one.
+ */
+in_rtchange(inp)
+       register struct inpcb *inp;
+{
+       if (inp->inp_route.ro_rt) {
+               rtfree(inp->inp_route.ro_rt);
+               inp->inp_route.ro_rt = 0;
+               /*
+                * A new route can be allocated the next time
+                * output is attempted.
+                */
+       }
+}
+
+struct inpcb *
+in_pcblookup(head, faddr, fport, laddr, lport, flags)
+       struct inpcb *head;
+       struct in_addr faddr, laddr;
+       u_short fport, lport;
+       int flags;
+{
+       register struct inpcb *inp, *match = 0;
+       int matchwild = 3, wildcard;
+
+       for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
+               if (inp->inp_lport != lport)
+                       continue;
+               wildcard = 0;
+               if (inp->inp_laddr.s_addr != INADDR_ANY) {
+                       if (laddr.s_addr == INADDR_ANY)
+                               wildcard++;
+                       else if (inp->inp_laddr.s_addr != laddr.s_addr)
+                               continue;
+               } else {
+                       if (laddr.s_addr != INADDR_ANY)
+                               wildcard++;
+               }
+               if (inp->inp_faddr.s_addr != INADDR_ANY) {
+                       if (faddr.s_addr == INADDR_ANY)
+                               wildcard++;
+                       else if (inp->inp_faddr.s_addr != faddr.s_addr ||
+                           inp->inp_fport != fport)
+                               continue;
+               } else {
+                       if (faddr.s_addr != INADDR_ANY)
+                               wildcard++;
+               }
+               if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
+                       continue;
+               if (wildcard < matchwild) {
+                       match = inp;
+                       matchwild = wildcard;
+                       if (matchwild == 0)
+                               break;
+               }
+       }
+       return (match);
+}
diff --git a/usr/src/sys.386bsd/netinet/in_pcb.h b/usr/src/sys.386bsd/netinet/in_pcb.h
new file mode 100644 (file)
index 0000000..efbd4e2
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in_pcb.h    7.6 (Berkeley) 6/28/90
+ */
+
+/*
+ * Common structure pcb for internet protocol implementation.
+ * Here are stored pointers to local and foreign host table
+ * entries, local and foreign socket numbers, and pointers
+ * up (to a socket structure) and down (to a protocol-specific)
+ * control block.
+ */
+struct inpcb {
+       struct  inpcb *inp_next,*inp_prev;
+                                       /* pointers to other pcb's */
+       struct  inpcb *inp_head;        /* pointer back to chain of inpcb's
+                                          for this protocol */
+       struct  in_addr inp_faddr;      /* foreign host table entry */
+       u_short inp_fport;              /* foreign port */
+       struct  in_addr inp_laddr;      /* local host table entry */
+       u_short inp_lport;              /* local port */
+       struct  socket *inp_socket;     /* back pointer to socket */
+       caddr_t inp_ppcb;               /* pointer to per-protocol pcb */
+       struct  route inp_route;        /* placeholder for routing entry */
+       int     inp_flags;              /* generic IP/datagram flags */
+       struct  ip inp_ip;              /* header prototype; should have more */
+       struct  mbuf *inp_options;      /* IP options */
+};
+
+/* flags in inp_flags: */
+#define        INP_RECVOPTS            0x01    /* receive incoming IP options */
+#define        INP_RECVRETOPTS         0x02    /* receive IP options for reply */
+#define        INP_RECVDSTADDR         0x04    /* receive IP dst address */
+#define        INP_CONTROLOPTS         (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR)
+
+#ifdef sotorawcb
+/*
+ * Common structure pcb for raw internet protocol access.
+ * Here are internet specific extensions to the raw control block,
+ * and space is allocated to the necessary sockaddrs.
+ */
+struct raw_inpcb {
+       struct  rawcb rinp_rcb; /* common control block prefix */
+       struct  mbuf *rinp_options;     /* IP options */
+       int     rinp_flags;             /* flags, e.g. raw sockopts */
+#define        RINPF_HDRINCL   0x1             /* user supplies entire IP header */
+       struct  sockaddr_in rinp_faddr; /* foreign address */
+       struct  sockaddr_in rinp_laddr; /* local address */
+       struct  route rinp_route;       /* placeholder for routing entry */
+};
+#endif
+
+#define        INPLOOKUP_WILDCARD      1
+#define        INPLOOKUP_SETLOCAL      2
+
+#define        sotoinpcb(so)   ((struct inpcb *)(so)->so_pcb)
+#define        sotorawinpcb(so)        ((struct raw_inpcb *)(so)->so_pcb)
+
+#ifdef KERNEL
+struct inpcb *in_pcblookup();
+#endif
diff --git a/usr/src/sys.386bsd/netinet/in_systm.h b/usr/src/sys.386bsd/netinet/in_systm.h
new file mode 100644 (file)
index 0000000..c246a59
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in_systm.h  7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Miscellaneous internetwork
+ * definitions for kernel.
+ */
+
+/*
+ * Network types.
+ *
+ * Internally the system keeps counters in the headers with the bytes
+ * swapped so that VAX instructions will work on them.  It reverses
+ * the bytes before transmission at each protocol level.  The n_ types
+ * represent the types with the bytes in ``high-ender'' order.
+ */
+typedef u_short n_short;               /* short as received from the net */
+typedef u_long n_long;                 /* long as received from the net */
+
+typedef        u_long  n_time;                 /* ms since 00:00 GMT, byte rev */
+
+#ifdef KERNEL
+n_time iptime();
+#endif
diff --git a/usr/src/sys.386bsd/netinet/in_var.h b/usr/src/sys.386bsd/netinet/in_var.h
new file mode 100644 (file)
index 0000000..72c48bb
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1985, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in_var.h    7.6 (Berkeley) 6/28/90
+ */
+
+/*
+ * Interface address, Internet version.  One of these structures
+ * is allocated for each interface with an Internet address.
+ * The ifaddr structure contains the protocol-independent part
+ * of the structure and is assumed to be first.
+ */
+struct in_ifaddr {
+       struct  ifaddr ia_ifa;          /* protocol-independent info */
+#define        ia_ifp          ia_ifa.ifa_ifp
+#define ia_flags       ia_ifa.ifa_flags
+                                       /* ia_{,sub}net{,mask} in host order */
+       u_long  ia_net;                 /* network number of interface */
+       u_long  ia_netmask;             /* mask of net part */
+       u_long  ia_subnet;              /* subnet number, including net */
+       u_long  ia_subnetmask;          /* mask of subnet part */
+       struct  in_addr ia_netbroadcast; /* to recognize net broadcasts */
+       struct  in_ifaddr *ia_next;     /* next in list of internet addresses */
+       struct  sockaddr_in ia_addr;    /* reserve space for interface name */
+       struct  sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
+#define        ia_broadaddr    ia_dstaddr
+       struct  sockaddr_in ia_sockmask; /* reserve space for general netmask */
+};
+
+struct in_aliasreq {
+       char    ifra_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+       struct  sockaddr_in ifra_addr;
+       struct  sockaddr_in ifra_broadaddr;
+#define ifra_dstaddr ifra_broadaddr
+       struct  sockaddr_in ifra_mask;
+};
+/*
+ * Given a pointer to an in_ifaddr (ifaddr),
+ * return a pointer to the addr as a sockaddr_in.
+ */
+#define        IA_SIN(ia) (&(((struct in_ifaddr *)(ia))->ia_addr))
+
+#ifdef KERNEL
+struct in_ifaddr *in_ifaddr;
+struct in_ifaddr *in_iaonnetof();
+struct ifqueue ipintrq;                /* ip packet input queue */
+#endif
diff --git a/usr/src/sys.386bsd/netinet/ip.h b/usr/src/sys.386bsd/netinet/ip.h
new file mode 100644 (file)
index 0000000..751dc4d
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ip.h        7.10 (Berkeley) 6/28/90
+ */
+
+/*
+ * Definitions for internet protocol version 4.
+ * Per RFC 791, September 1981.
+ */
+#define        IPVERSION       4
+
+/*
+ * Structure of an internet header, naked of options.
+ *
+ * We declare ip_len and ip_off to be short, rather than u_short
+ * pragmatically since otherwise unsigned comparisons can result
+ * against negative integers quite easily, and fail in subtle ways.
+ */
+struct ip {
+#if BYTE_ORDER == LITTLE_ENDIAN 
+       u_char  ip_hl:4,                /* header length */
+               ip_v:4;                 /* version */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN 
+       u_char  ip_v:4,                 /* version */
+               ip_hl:4;                /* header length */
+#endif
+       u_char  ip_tos;                 /* type of service */
+       short   ip_len;                 /* total length */
+       u_short ip_id;                  /* identification */
+       short   ip_off;                 /* fragment offset field */
+#define        IP_DF 0x4000                    /* dont fragment flag */
+#define        IP_MF 0x2000                    /* more fragments flag */
+       u_char  ip_ttl;                 /* time to live */
+       u_char  ip_p;                   /* protocol */
+       u_short ip_sum;                 /* checksum */
+       struct  in_addr ip_src,ip_dst;  /* source and dest address */
+};
+
+#define        IP_MAXPACKET    65535           /* maximum packet size */
+
+/*
+ * Definitions for IP type of service (ip_tos)
+ */
+#define        IPTOS_LOWDELAY          0x10
+#define        IPTOS_THROUGHPUT        0x08
+#define        IPTOS_RELIABILITY       0x04
+
+/*
+ * Definitions for IP precedence (also in ip_tos) (hopefully unused)
+ */
+#define        IPTOS_PREC_NETCONTROL           0xe0
+#define        IPTOS_PREC_INTERNETCONTROL      0xc0
+#define        IPTOS_PREC_CRITIC_ECP           0xa0
+#define        IPTOS_PREC_FLASHOVERRIDE        0x80
+#define        IPTOS_PREC_FLASH                0x60
+#define        IPTOS_PREC_IMMEDIATE            0x40
+#define        IPTOS_PREC_PRIORITY             0x20
+#define        IPTOS_PREC_ROUTINE              0x10
+
+/*
+ * Definitions for options.
+ */
+#define        IPOPT_COPIED(o)         ((o)&0x80)
+#define        IPOPT_CLASS(o)          ((o)&0x60)
+#define        IPOPT_NUMBER(o)         ((o)&0x1f)
+
+#define        IPOPT_CONTROL           0x00
+#define        IPOPT_RESERVED1         0x20
+#define        IPOPT_DEBMEAS           0x40
+#define        IPOPT_RESERVED2         0x60
+
+#define        IPOPT_EOL               0               /* end of option list */
+#define        IPOPT_NOP               1               /* no operation */
+
+#define        IPOPT_RR                7               /* record packet route */
+#define        IPOPT_TS                68              /* timestamp */
+#define        IPOPT_SECURITY          130             /* provide s,c,h,tcc */
+#define        IPOPT_LSRR              131             /* loose source route */
+#define        IPOPT_SATID             136             /* satnet id */
+#define        IPOPT_SSRR              137             /* strict source route */
+
+/*
+ * Offsets to fields in options other than EOL and NOP.
+ */
+#define        IPOPT_OPTVAL            0               /* option ID */
+#define        IPOPT_OLEN              1               /* option length */
+#define IPOPT_OFFSET           2               /* offset within option */
+#define        IPOPT_MINOFF            4               /* min value of above */
+
+/*
+ * Time stamp option structure.
+ */
+struct ip_timestamp {
+       u_char  ipt_code;               /* IPOPT_TS */
+       u_char  ipt_len;                /* size of structure (variable) */
+       u_char  ipt_ptr;                /* index of current entry */
+#if BYTE_ORDER == LITTLE_ENDIAN 
+       u_char  ipt_flg:4,              /* flags, see below */
+               ipt_oflw:4;             /* overflow counter */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN 
+       u_char  ipt_oflw:4,             /* overflow counter */
+               ipt_flg:4;              /* flags, see below */
+#endif
+       union ipt_timestamp {
+               n_long  ipt_time[1];
+               struct  ipt_ta {
+                       struct in_addr ipt_addr;
+                       n_long ipt_time;
+               } ipt_ta[1];
+       } ipt_timestamp;
+};
+
+/* flag bits for ipt_flg */
+#define        IPOPT_TS_TSONLY         0               /* timestamps only */
+#define        IPOPT_TS_TSANDADDR      1               /* timestamps and addresses */
+#define        IPOPT_TS_PRESPEC        3               /* specified modules only */
+
+/* bits for security (not byte swapped) */
+#define        IPOPT_SECUR_UNCLASS     0x0000
+#define        IPOPT_SECUR_CONFID      0xf135
+#define        IPOPT_SECUR_EFTO        0x789a
+#define        IPOPT_SECUR_MMMM        0xbc4d
+#define        IPOPT_SECUR_RESTR       0xaf13
+#define        IPOPT_SECUR_SECRET      0xd788
+#define        IPOPT_SECUR_TOPSECRET   0x6bc5
+
+/*
+ * Internet implementation parameters.
+ */
+#define        MAXTTL          255             /* maximum time to live (seconds) */
+#define        IPFRAGTTL       60              /* time to live for frags, slowhz */
+#define        IPTTLDEC        1               /* subtracted when forwarding */
+
+#define        IP_MSS          576             /* default maximum segment size */
diff --git a/usr/src/sys.386bsd/netinet/ip_icmp.c b/usr/src/sys.386bsd/netinet/ip_icmp.c
new file mode 100644 (file)
index 0000000..69815bd
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ip_icmp.c   7.15 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "time.h"
+#include "kernel.h"
+
+#include "../net/route.h"
+#include "../net/if.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "in_var.h"
+#include "ip.h"
+#include "ip_icmp.h"
+#include "icmp_var.h"
+
+/*
+ * ICMP routines: error generation, receive packet processing, and
+ * routines to turnaround packets back to the originator, and
+ * host table maintenance routines.
+ */
+#ifdef ICMPPRINTFS
+int    icmpprintfs = 0;
+#endif
+
+extern struct protosw inetsw[];
+
+/*
+ * Generate an error packet of type error
+ * in response to bad packet ip.
+ */
+/*VARARGS3*/
+icmp_error(n, type, code, dest)
+       struct mbuf *n;
+       int type, code;
+       struct in_addr dest;
+{
+       register struct ip *oip = mtod(n, struct ip *), *nip;
+       register unsigned oiplen = oip->ip_hl << 2;
+       register struct icmp *icp;
+       register struct mbuf *m;
+       unsigned icmplen;
+
+#ifdef ICMPPRINTFS
+       if (icmpprintfs)
+               printf("icmp_error(%x, %d, %d)\n", oip, type, code);
+#endif
+       if (type != ICMP_REDIRECT)
+               icmpstat.icps_error++;
+       /*
+        * Don't send error if not the first fragment of message.
+        * Don't error if the old packet protocol was ICMP
+        * error message, only known informational types.
+        */
+       if (oip->ip_off &~ (IP_MF|IP_DF))
+               goto freeit;
+       if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
+         n->m_len >= oiplen + ICMP_MINLEN &&
+         !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
+               icmpstat.icps_oldicmp++;
+               goto freeit;
+       }
+
+       /*
+        * First, formulate icmp message
+        */
+       m = m_gethdr(M_DONTWAIT, MT_HEADER);
+       if (m == NULL)
+               goto freeit;
+       icmplen = oiplen + min(8, oip->ip_len);
+       m->m_len = icmplen + ICMP_MINLEN;
+       MH_ALIGN(m, m->m_len);
+       icp = mtod(m, struct icmp *);
+       if ((u_int)type > ICMP_MAXTYPE)
+               panic("icmp_error");
+       icmpstat.icps_outhist[type]++;
+       icp->icmp_type = type;
+       if (type == ICMP_REDIRECT)
+               icp->icmp_gwaddr = dest;
+       else
+               icp->icmp_void = 0;
+       if (type == ICMP_PARAMPROB) {
+               icp->icmp_pptr = code;
+               code = 0;
+       }
+       icp->icmp_code = code;
+       bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
+       nip = &icp->icmp_ip;
+       nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
+
+       /*
+        * Now, copy old ip header (without options)
+        * in front of icmp message.
+        */
+       if (m->m_data - sizeof(struct ip) < m->m_pktdat)
+               panic("icmp len");
+       m->m_data -= sizeof(struct ip);
+       m->m_len += sizeof(struct ip);
+       m->m_pkthdr.len = m->m_len;
+       m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
+       nip = mtod(m, struct ip *);
+       bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
+       nip->ip_len = m->m_len;
+       nip->ip_hl = sizeof(struct ip) >> 2;
+       nip->ip_p = IPPROTO_ICMP;
+       icmp_reflect(m);
+
+freeit:
+       m_freem(n);
+}
+
+static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
+static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
+static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
+static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
+struct sockaddr_in icmpmask = { 8, 0 };
+struct in_ifaddr *ifptoia();
+
+/*
+ * Process a received ICMP message.
+ */
+icmp_input(m, hlen)
+       register struct mbuf *m;
+       int hlen;
+{
+       register struct icmp *icp;
+       register struct ip *ip = mtod(m, struct ip *);
+       int icmplen = ip->ip_len;
+       register int i;
+       struct in_ifaddr *ia;
+       int (*ctlfunc)(), code;
+       extern u_char ip_protox[];
+       extern struct in_addr in_makeaddr();
+
+       /*
+        * Locate icmp structure in mbuf, and check
+        * that not corrupted and of at least minimum length.
+        */
+#ifdef ICMPPRINTFS
+       if (icmpprintfs)
+               printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
+#endif
+       if (icmplen < ICMP_MINLEN) {
+               icmpstat.icps_tooshort++;
+               goto freeit;
+       }
+       i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
+       if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
+               icmpstat.icps_tooshort++;
+               return;
+       }
+       ip = mtod(m, struct ip *);
+       m->m_len -= hlen;
+       m->m_data += hlen;
+       icp = mtod(m, struct icmp *);
+       if (in_cksum(m, icmplen)) {
+               icmpstat.icps_checksum++;
+               goto freeit;
+       }
+       m->m_len += hlen;
+       m->m_data -= hlen;
+
+#ifdef ICMPPRINTFS
+       /*
+        * Message type specific processing.
+        */
+       if (icmpprintfs)
+               printf("icmp_input, type %d code %d\n", icp->icmp_type,
+                   icp->icmp_code);
+#endif
+       if (icp->icmp_type > ICMP_MAXTYPE)
+               goto raw;
+       icmpstat.icps_inhist[icp->icmp_type]++;
+       code = icp->icmp_code;
+       switch (icp->icmp_type) {
+
+       case ICMP_UNREACH:
+               if (code > 5)
+                       goto badcode;
+               code += PRC_UNREACH_NET;
+               goto deliver;
+
+       case ICMP_TIMXCEED:
+               if (code > 1)
+                       goto badcode;
+               code += PRC_TIMXCEED_INTRANS;
+               goto deliver;
+
+       case ICMP_PARAMPROB:
+               if (code)
+                       goto badcode;
+               code = PRC_PARAMPROB;
+               goto deliver;
+
+       case ICMP_SOURCEQUENCH:
+               if (code)
+                       goto badcode;
+               code = PRC_QUENCH;
+       deliver:
+               /*
+                * Problem with datagram; advise higher level routines.
+                */
+               if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
+                   icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
+                       icmpstat.icps_badlen++;
+                       goto freeit;
+               }
+               NTOHS(icp->icmp_ip.ip_len);
+#ifdef ICMPPRINTFS
+               if (icmpprintfs)
+                       printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
+#endif
+               icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
+               if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
+                       (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
+                           (caddr_t) &icp->icmp_ip);
+               break;
+
+       badcode:
+               icmpstat.icps_badcode++;
+               break;
+
+       case ICMP_ECHO:
+               icp->icmp_type = ICMP_ECHOREPLY;
+               goto reflect;
+
+       case ICMP_TSTAMP:
+               if (icmplen < ICMP_TSLEN) {
+                       icmpstat.icps_badlen++;
+                       break;
+               }
+               icp->icmp_type = ICMP_TSTAMPREPLY;
+               icp->icmp_rtime = iptime();
+               icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
+               goto reflect;
+               
+       case ICMP_IREQ:
+#define        satosin(sa)     ((struct sockaddr_in *)(sa))
+               if (in_netof(ip->ip_src) == 0 &&
+                   (ia = ifptoia(m->m_pkthdr.rcvif)))
+                       ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
+                           in_lnaof(ip->ip_src));
+               icp->icmp_type = ICMP_IREQREPLY;
+               goto reflect;
+
+       case ICMP_MASKREQ:
+               if (icmplen < ICMP_MASKLEN ||
+                   (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
+                       break;
+               icp->icmp_type = ICMP_MASKREPLY;
+               icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
+               if (ip->ip_src.s_addr == 0) {
+                       if (ia->ia_ifp->if_flags & IFF_BROADCAST)
+                           ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
+                       else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
+                           ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
+               }
+reflect:
+               ip->ip_len += hlen;     /* since ip_input deducts this */
+               icmpstat.icps_reflect++;
+               icmpstat.icps_outhist[icp->icmp_type]++;
+               icmp_reflect(m);
+               return;
+
+       case ICMP_REDIRECT:
+               if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
+                       icmpstat.icps_badlen++;
+                       break;
+               }
+               /*
+                * Short circuit routing redirects to force
+                * immediate change in the kernel's routing
+                * tables.  The message is also handed to anyone
+                * listening on a raw socket (e.g. the routing
+                * daemon for use in updating its tables).
+                */
+               icmpgw.sin_addr = ip->ip_src;
+               icmpdst.sin_addr = icp->icmp_gwaddr;
+#ifdef ICMPPRINTFS
+               if (icmpprintfs)
+                       printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
+                               icp->icmp_gwaddr);
+#endif
+               if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
+                       u_long in_netof();
+                       icmpsrc.sin_addr =
+                        in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
+                       in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask);
+                       rtredirect((struct sockaddr *)&icmpsrc,
+                         (struct sockaddr *)&icmpdst,
+                         (struct sockaddr *)&icmpmask, RTF_GATEWAY,
+                         (struct sockaddr *)&icmpgw, (struct rtentry **)0);
+                       icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
+                       pfctlinput(PRC_REDIRECT_NET,
+                         (struct sockaddr *)&icmpsrc);
+               } else {
+                       icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
+                       rtredirect((struct sockaddr *)&icmpsrc,
+                         (struct sockaddr *)&icmpdst,
+                         (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
+                         (struct sockaddr *)&icmpgw, (struct rtentry **)0);
+                       pfctlinput(PRC_REDIRECT_HOST,
+                         (struct sockaddr *)&icmpsrc);
+               }
+               break;
+
+       /*
+        * No kernel processing for the following;
+        * just fall through to send to raw listener.
+        */
+       case ICMP_ECHOREPLY:
+       case ICMP_TSTAMPREPLY:
+       case ICMP_IREQREPLY:
+       case ICMP_MASKREPLY:
+       default:
+               break;
+       }
+
+raw:
+       icmpsrc.sin_addr = ip->ip_src;
+       icmpdst.sin_addr = ip->ip_dst;
+       (void) raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
+           (struct sockaddr *)&icmpdst);
+       return;
+
+freeit:
+       m_freem(m);
+}
+
+/*
+ * Reflect the ip packet back to the source
+ */
+icmp_reflect(m)
+       struct mbuf *m;
+{
+       register struct ip *ip = mtod(m, struct ip *);
+       register struct in_ifaddr *ia;
+       struct in_addr t;
+       struct mbuf *opts = 0, *ip_srcroute();
+       int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
+
+       t = ip->ip_dst;
+       ip->ip_dst = ip->ip_src;
+       /*
+        * If the incoming packet was addressed directly to us,
+        * use dst as the src for the reply.  Otherwise (broadcast
+        * or anonymous), use the address which corresponds
+        * to the incoming interface.
+        */
+       for (ia = in_ifaddr; ia; ia = ia->ia_next) {
+               if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
+                       break;
+               if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
+                   t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
+                       break;
+       }
+       if (ia == (struct in_ifaddr *)0)
+               ia = ifptoia(m->m_pkthdr.rcvif);
+       if (ia == (struct in_ifaddr *)0)
+               ia = in_ifaddr;
+       t = IA_SIN(ia)->sin_addr;
+       ip->ip_src = t;
+       ip->ip_ttl = MAXTTL;
+
+       if (optlen > 0) {
+               register u_char *cp;
+               int opt, cnt;
+               u_int len;
+
+               /*
+                * Retrieve any source routing from the incoming packet;
+                * add on any record-route or timestamp options.
+                */
+               cp = (u_char *) (ip + 1);
+               if ((opts = ip_srcroute()) == 0 &&
+                   (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
+                       opts->m_len = sizeof(struct in_addr);
+                       mtod(opts, struct in_addr *)->s_addr = 0;
+               }
+               if (opts) {
+#ifdef ICMPPRINTFS
+                   if (icmpprintfs)
+                           printf("icmp_reflect optlen %d rt %d => ",
+                               optlen, opts->m_len);
+#endif
+                   for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
+                           opt = cp[IPOPT_OPTVAL];
+                           if (opt == IPOPT_EOL)
+                                   break;
+                           if (opt == IPOPT_NOP)
+                                   len = 1;
+                           else {
+                                   len = cp[IPOPT_OLEN];
+                                   if (len <= 0 || len > cnt)
+                                           break;
+                           }
+                           /*
+                            * should check for overflow, but it "can't happen"
+                            */
+                           if (opt == IPOPT_RR || opt == IPOPT_TS) {
+                                   bcopy((caddr_t)cp,
+                                       mtod(opts, caddr_t) + opts->m_len, len);
+                                   opts->m_len += len;
+                           }
+                   }
+                   if (opts->m_len % 4 != 0) {
+                           *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL;
+                           opts->m_len++;
+                   }
+#ifdef ICMPPRINTFS
+                   if (icmpprintfs)
+                           printf("%d\n", opts->m_len);
+#endif
+               }
+               /*
+                * Now strip out original options by copying rest of first
+                * mbuf's data back, and adjust the IP length.
+                */
+               ip->ip_len -= optlen;
+               ip->ip_hl = sizeof(struct ip) >> 2;
+               m->m_len -= optlen;
+               if (m->m_flags & M_PKTHDR)
+                       m->m_pkthdr.len -= optlen;
+               optlen += sizeof(struct ip);
+               bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
+                        (unsigned)(m->m_len - sizeof(struct ip)));
+       }
+       icmp_send(m, opts);
+       if (opts)
+               (void)m_free(opts);
+}
+
+struct in_ifaddr *
+ifptoia(ifp)
+       struct ifnet *ifp;
+{
+       register struct in_ifaddr *ia;
+
+       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+               if (ia->ia_ifp == ifp)
+                       return (ia);
+       return ((struct in_ifaddr *)0);
+}
+
+/*
+ * Send an icmp packet back to the ip level,
+ * after supplying a checksum.
+ */
+icmp_send(m, opts)
+       register struct mbuf *m;
+       struct mbuf *opts;
+{
+       register struct ip *ip = mtod(m, struct ip *);
+       register int hlen;
+       register struct icmp *icp;
+
+       hlen = ip->ip_hl << 2;
+       m->m_data += hlen;
+       m->m_len -= hlen;
+       icp = mtod(m, struct icmp *);
+       icp->icmp_cksum = 0;
+       icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
+       m->m_data -= hlen;
+       m->m_len += hlen;
+#ifdef ICMPPRINTFS
+       if (icmpprintfs)
+               printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
+#endif
+       (void) ip_output(m, opts, (struct route *)0, 0);
+}
+
+n_time
+iptime()
+{
+       struct timeval atv;
+       u_long t;
+
+       microtime(&atv);
+       t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
+       return (htonl(t));
+}
diff --git a/usr/src/sys.386bsd/netinet/ip_icmp.h b/usr/src/sys.386bsd/netinet/ip_icmp.h
new file mode 100644 (file)
index 0000000..10bf7fc
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ip_icmp.h   7.5 (Berkeley) 6/28/90
+ */
+
+/*
+ * Interface Control Message Protocol Definitions.
+ * Per RFC 792, September 1981.
+ */
+
+/*
+ * Structure of an icmp header.
+ */
+struct icmp {
+       u_char  icmp_type;              /* type of message, see below */
+       u_char  icmp_code;              /* type sub code */
+       u_short icmp_cksum;             /* ones complement cksum of struct */
+       union {
+               u_char ih_pptr;                 /* ICMP_PARAMPROB */
+               struct in_addr ih_gwaddr;       /* ICMP_REDIRECT */
+               struct ih_idseq {
+                       n_short icd_id;
+                       n_short icd_seq;
+               } ih_idseq;
+               int ih_void;
+       } icmp_hun;
+#define        icmp_pptr       icmp_hun.ih_pptr
+#define        icmp_gwaddr     icmp_hun.ih_gwaddr
+#define        icmp_id         icmp_hun.ih_idseq.icd_id
+#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
+#define        icmp_void       icmp_hun.ih_void
+       union {
+               struct id_ts {
+                       n_time its_otime;
+                       n_time its_rtime;
+                       n_time its_ttime;
+               } id_ts;
+               struct id_ip  {
+                       struct ip idi_ip;
+                       /* options and then 64 bits of data */
+               } id_ip;
+               u_long  id_mask;
+               char    id_data[1];
+       } icmp_dun;
+#define        icmp_otime      icmp_dun.id_ts.its_otime
+#define        icmp_rtime      icmp_dun.id_ts.its_rtime
+#define        icmp_ttime      icmp_dun.id_ts.its_ttime
+#define        icmp_ip         icmp_dun.id_ip.idi_ip
+#define        icmp_mask       icmp_dun.id_mask
+#define        icmp_data       icmp_dun.id_data
+};
+
+/*
+ * Lower bounds on packet lengths for various types.
+ * For the error advice packets must first insure that the
+ * packet is large enought to contain the returned ip header.
+ * Only then can we do the check to see if 64 bits of packet
+ * data have been returned, since we need to check the returned
+ * ip header length.
+ */
+#define        ICMP_MINLEN     8                               /* abs minimum */
+#define        ICMP_TSLEN      (8 + 3 * sizeof (n_time))       /* timestamp */
+#define        ICMP_MASKLEN    12                              /* address mask */
+#define        ICMP_ADVLENMIN  (8 + sizeof (struct ip) + 8)    /* min */
+#define        ICMP_ADVLEN(p)  (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
+       /* N.B.: must separately check that ip_hl >= 5 */
+
+/*
+ * Definition of type and code field values.
+ */
+#define        ICMP_ECHOREPLY          0               /* echo reply */
+#define        ICMP_UNREACH            3               /* dest unreachable, codes: */
+#define                ICMP_UNREACH_NET        0               /* bad net */
+#define                ICMP_UNREACH_HOST       1               /* bad host */
+#define                ICMP_UNREACH_PROTOCOL   2               /* bad protocol */
+#define                ICMP_UNREACH_PORT       3               /* bad port */
+#define                ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
+#define                ICMP_UNREACH_SRCFAIL    5               /* src route failed */
+#define        ICMP_SOURCEQUENCH       4               /* packet lost, slow down */
+#define        ICMP_REDIRECT           5               /* shorter route, codes: */
+#define                ICMP_REDIRECT_NET       0               /* for network */
+#define                ICMP_REDIRECT_HOST      1               /* for host */
+#define                ICMP_REDIRECT_TOSNET    2               /* for tos and net */
+#define                ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
+#define        ICMP_ECHO               8               /* echo service */
+#define        ICMP_TIMXCEED           11              /* time exceeded, code: */
+#define                ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
+#define                ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
+#define        ICMP_PARAMPROB          12              /* ip header bad */
+#define        ICMP_TSTAMP             13              /* timestamp request */
+#define        ICMP_TSTAMPREPLY        14              /* timestamp reply */
+#define        ICMP_IREQ               15              /* information request */
+#define        ICMP_IREQREPLY          16              /* information reply */
+#define        ICMP_MASKREQ            17              /* address mask request */
+#define        ICMP_MASKREPLY          18              /* address mask reply */
+
+#define        ICMP_MAXTYPE            18
+
+#define        ICMP_INFOTYPE(type) \
+       ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
+       (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
+       (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
+       (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
diff --git a/usr/src/sys.386bsd/netinet/ip_input.c b/usr/src/sys.386bsd/netinet/ip_input.c
new file mode 100644 (file)
index 0000000..889e370
--- /dev/null
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ip_input.c  7.19 (Berkeley) 5/25/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "domain.h"
+#include "protosw.h"
+#include "socket.h"
+#include "errno.h"
+#include "time.h"
+#include "kernel.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "in_var.h"
+#include "ip_var.h"
+#include "ip_icmp.h"
+
+#ifndef        IPFORWARDING
+#ifdef GATEWAY
+#define        IPFORWARDING    1       /* forward IP packets not for us */
+#else /* GATEWAY */
+#define        IPFORWARDING    0       /* don't forward IP packets not for us */
+#endif /* GATEWAY */
+#endif /* IPFORWARDING */
+#ifndef        IPSENDREDIRECTS
+#define        IPSENDREDIRECTS 1
+#endif
+int    ipforwarding = IPFORWARDING;
+int    ipsendredirects = IPSENDREDIRECTS;
+#ifdef DIAGNOSTIC
+int    ipprintfs = 0;
+#endif
+
+extern struct domain inetdomain;
+extern struct protosw inetsw[];
+u_char ip_protox[IPPROTO_MAX];
+int    ipqmaxlen = IFQ_MAXLEN;
+struct in_ifaddr *in_ifaddr;                   /* first inet address */
+
+/*
+ * We need to save the IP options in case a protocol wants to respond
+ * to an incoming packet over the same route if the packet got here
+ * using IP source routing.  This allows connection establishment and
+ * maintenance when the remote end is on a network that is not known
+ * to us.
+ */
+int    ip_nhops = 0;
+static struct ip_srcrt {
+       struct  in_addr dst;                    /* final destination */
+       char    nop;                            /* one NOP to align */
+       char    srcopt[IPOPT_OFFSET + 1];       /* OPTVAL, OLEN and OFFSET */
+       struct  in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
+} ip_srcrt;
+
+#ifdef GATEWAY
+extern int if_index;
+u_long *ip_ifmatrix;
+#endif
+
+/*
+ * IP initialization: fill in IP protocol switch table.
+ * All protocols not implemented in kernel go to raw IP protocol handler.
+ */
+ip_init()
+{
+       register struct protosw *pr;
+       register int i;
+
+       pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
+       if (pr == 0)
+               panic("ip_init");
+       for (i = 0; i < IPPROTO_MAX; i++)
+               ip_protox[i] = pr - inetsw;
+       for (pr = inetdomain.dom_protosw;
+           pr < inetdomain.dom_protoswNPROTOSW; pr++)
+               if (pr->pr_domain->dom_family == PF_INET &&
+                   pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
+                       ip_protox[pr->pr_protocol] = pr - inetsw;
+       ipq.next = ipq.prev = &ipq;
+       ip_id = time.tv_sec & 0xffff;
+       ipintrq.ifq_maxlen = ipqmaxlen;
+#ifdef GATEWAY
+       i = (if_index + 1) * (if_index + 1) * sizeof (u_long);
+       if ((ip_ifmatrix = (u_long *) malloc(i, M_RTABLE, M_WAITOK)) == 0)
+               panic("no memory for ip_ifmatrix");
+#endif
+}
+
+struct ip *ip_reass();
+struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
+struct route ipforward_rt;
+
+/*
+ * Ip input routine.  Checksum and byte swap header.  If fragmented
+ * try to reassemble.  Process options.  Pass to next level.
+ */
+ipintr()
+{
+       register struct ip *ip;
+       register struct mbuf *m;
+       register struct ipq *fp;
+       register struct in_ifaddr *ia;
+       int hlen, s;
+
+next:
+       /*
+        * Get next datagram off input queue and get IP header
+        * in first mbuf.
+        */
+       s = splimp();
+       IF_DEQUEUE(&ipintrq, m);
+       splx(s);
+       if (m == 0)
+               return;
+#ifdef DIAGNOSTIC
+       if ((m->m_flags & M_PKTHDR) == 0)
+               panic("ipintr no HDR");
+#endif
+       /*
+        * If no IP addresses have been set yet but the interfaces
+        * are receiving, can't do anything with incoming packets yet.
+        */
+       if (in_ifaddr == NULL)
+               goto bad;
+       ipstat.ips_total++;
+       if (m->m_len < sizeof (struct ip) &&
+           (m = m_pullup(m, sizeof (struct ip))) == 0) {
+               ipstat.ips_toosmall++;
+               goto next;
+       }
+       ip = mtod(m, struct ip *);
+       hlen = ip->ip_hl << 2;
+       if (hlen < sizeof(struct ip)) { /* minimum header length */
+               ipstat.ips_badhlen++;
+               goto bad;
+       }
+       if (hlen > m->m_len) {
+               if ((m = m_pullup(m, hlen)) == 0) {
+                       ipstat.ips_badhlen++;
+                       goto next;
+               }
+               ip = mtod(m, struct ip *);
+       }
+       if (ip->ip_sum = in_cksum(m, hlen)) {
+               ipstat.ips_badsum++;
+               goto bad;
+       }
+
+       /*
+        * Convert fields to host representation.
+        */
+       NTOHS(ip->ip_len);
+       if (ip->ip_len < hlen) {
+               ipstat.ips_badlen++;
+               goto bad;
+       }
+       NTOHS(ip->ip_id);
+       NTOHS(ip->ip_off);
+
+       /*
+        * Check that the amount of data in the buffers
+        * is as at least much as the IP header would have us expect.
+        * Trim mbufs if longer than we expect.
+        * Drop packet if shorter than we expect.
+        */
+       if (m->m_pkthdr.len < ip->ip_len) {
+               ipstat.ips_tooshort++;
+               goto bad;
+       }
+       if (m->m_pkthdr.len > ip->ip_len) {
+               if (m->m_len == m->m_pkthdr.len) {
+                       m->m_len = ip->ip_len;
+                       m->m_pkthdr.len = ip->ip_len;
+               } else
+                       m_adj(m, ip->ip_len - m->m_pkthdr.len);
+       }
+
+       /*
+        * Process options and, if not destined for us,
+        * ship it on.  ip_dooptions returns 1 when an
+        * error was detected (causing an icmp message
+        * to be sent and the original packet to be freed).
+        */
+       ip_nhops = 0;           /* for source routed packets */
+       if (hlen > sizeof (struct ip) && ip_dooptions(m))
+               goto next;
+
+       /*
+        * Check our list of addresses, to see if the packet is for us.
+        */
+       for (ia = in_ifaddr; ia; ia = ia->ia_next) {
+#define        satosin(sa)     ((struct sockaddr_in *)(sa))
+
+               if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
+                       goto ours;
+               if (
+#ifdef DIRECTED_BROADCAST
+                   ia->ia_ifp == m->m_pkthdr.rcvif &&
+#endif
+                   (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
+                       u_long t;
+
+                       if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
+                           ip->ip_dst.s_addr)
+                               goto ours;
+                       if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
+                               goto ours;
+                       /*
+                        * Look for all-0's host part (old broadcast addr),
+                        * either for subnet or net.
+                        */
+                       t = ntohl(ip->ip_dst.s_addr);
+                       if (t == ia->ia_subnet)
+                               goto ours;
+                       if (t == ia->ia_net)
+                               goto ours;
+               }
+       }
+       if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
+               goto ours;
+       if (ip->ip_dst.s_addr == INADDR_ANY)
+               goto ours;
+
+       /*
+        * Not for us; forward if possible and desirable.
+        */
+       if (ipforwarding == 0) {
+               ipstat.ips_cantforward++;
+               m_freem(m);
+       } else
+               ip_forward(m, 0);
+       goto next;
+
+ours:
+       /*
+        * If offset or IP_MF are set, must reassemble.
+        * Otherwise, nothing need be done.
+        * (We could look in the reassembly queue to see
+        * if the packet was previously fragmented,
+        * but it's not worth the time; just let them time out.)
+        */
+       if (ip->ip_off &~ IP_DF) {
+               if (m->m_flags & M_EXT) {               /* XXX */
+                       if ((m = m_pullup(m, sizeof (struct ip))) == 0) {
+                               ipstat.ips_toosmall++;
+                               goto next;
+                       }
+                       ip = mtod(m, struct ip *);
+               }
+               /*
+                * Look for queue of fragments
+                * of this datagram.
+                */
+               for (fp = ipq.next; fp != &ipq; fp = fp->next)
+                       if (ip->ip_id == fp->ipq_id &&
+                           ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+                           ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+                           ip->ip_p == fp->ipq_p)
+                               goto found;
+               fp = 0;
+found:
+
+               /*
+                * Adjust ip_len to not reflect header,
+                * set ip_mff if more fragments are expected,
+                * convert offset of this to bytes.
+                */
+               ip->ip_len -= hlen;
+               ((struct ipasfrag *)ip)->ipf_mff = 0;
+               if (ip->ip_off & IP_MF)
+                       ((struct ipasfrag *)ip)->ipf_mff = 1;
+               ip->ip_off <<= 3;
+
+               /*
+                * If datagram marked as having more fragments
+                * or if this is not the first fragment,
+                * attempt reassembly; if it succeeds, proceed.
+                */
+               if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
+                       ipstat.ips_fragments++;
+                       ip = ip_reass((struct ipasfrag *)ip, fp);
+                       if (ip == 0)
+                               goto next;
+                       else
+                               ipstat.ips_reassembled++;
+                       m = dtom(ip);
+               } else
+                       if (fp)
+                               ip_freef(fp);
+       } else
+               ip->ip_len -= hlen;
+
+       /*
+        * Switch out to protocol's input routine.
+        */
+       ipstat.ips_delivered++;
+       (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
+       goto next;
+bad:
+       m_freem(m);
+       goto next;
+}
+
+/*
+ * Take incoming datagram fragment and try to
+ * reassemble it into whole datagram.  If a chain for
+ * reassembly of this datagram already exists, then it
+ * is given as fp; otherwise have to make a chain.
+ */
+struct ip *
+ip_reass(ip, fp)
+       register struct ipasfrag *ip;
+       register struct ipq *fp;
+{
+       register struct mbuf *m = dtom(ip);
+       register struct ipasfrag *q;
+       struct mbuf *t;
+       int hlen = ip->ip_hl << 2;
+       int i, next;
+
+       /*
+        * Presence of header sizes in mbufs
+        * would confuse code below.
+        */
+       m->m_data += hlen;
+       m->m_len -= hlen;
+
+       /*
+        * If first fragment to arrive, create a reassembly queue.
+        */
+       if (fp == 0) {
+               if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
+                       goto dropfrag;
+               fp = mtod(t, struct ipq *);
+               insque(fp, &ipq);
+               fp->ipq_ttl = IPFRAGTTL;
+               fp->ipq_p = ip->ip_p;
+               fp->ipq_id = ip->ip_id;
+               fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
+               fp->ipq_src = ((struct ip *)ip)->ip_src;
+               fp->ipq_dst = ((struct ip *)ip)->ip_dst;
+               q = (struct ipasfrag *)fp;
+               goto insert;
+       }
+
+       /*
+        * Find a segment which begins after this one does.
+        */
+       for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
+               if (q->ip_off > ip->ip_off)
+                       break;
+
+       /*
+        * If there is a preceding segment, it may provide some of
+        * our data already.  If so, drop the data from the incoming
+        * segment.  If it provides all of our data, drop us.
+        */
+       if (q->ipf_prev != (struct ipasfrag *)fp) {
+               i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
+               if (i > 0) {
+                       if (i >= ip->ip_len)
+                               goto dropfrag;
+                       m_adj(dtom(ip), i);
+                       ip->ip_off += i;
+                       ip->ip_len -= i;
+               }
+       }
+
+       /*
+        * While we overlap succeeding segments trim them or,
+        * if they are completely covered, dequeue them.
+        */
+       while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
+               i = (ip->ip_off + ip->ip_len) - q->ip_off;
+               if (i < q->ip_len) {
+                       q->ip_len -= i;
+                       q->ip_off += i;
+                       m_adj(dtom(q), i);
+                       break;
+               }
+               q = q->ipf_next;
+               m_freem(dtom(q->ipf_prev));
+               ip_deq(q->ipf_prev);
+       }
+
+insert:
+       /*
+        * Stick new segment in its place;
+        * check for complete reassembly.
+        */
+       ip_enq(ip, q->ipf_prev);
+       next = 0;
+       for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
+               if (q->ip_off != next)
+                       return (0);
+               next += q->ip_len;
+       }
+       if (q->ipf_prev->ipf_mff)
+               return (0);
+
+       /*
+        * Reassembly is complete; concatenate fragments.
+        */
+       q = fp->ipq_next;
+       m = dtom(q);
+       t = m->m_next;
+       m->m_next = 0;
+       m_cat(m, t);
+       q = q->ipf_next;
+       while (q != (struct ipasfrag *)fp) {
+               t = dtom(q);
+               q = q->ipf_next;
+               m_cat(m, t);
+       }
+
+       /*
+        * Create header for new ip packet by
+        * modifying header of first packet;
+        * dequeue and discard fragment reassembly header.
+        * Make header visible.
+        */
+       ip = fp->ipq_next;
+       ip->ip_len = next;
+       ((struct ip *)ip)->ip_src = fp->ipq_src;
+       ((struct ip *)ip)->ip_dst = fp->ipq_dst;
+       remque(fp);
+       (void) m_free(dtom(fp));
+       m = dtom(ip);
+       m->m_len += (ip->ip_hl << 2);
+       m->m_data -= (ip->ip_hl << 2);
+       /* some debugging cruft by sklower, below, will go away soon */
+       if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
+               register int plen = 0;
+               for (t = m; m; m = m->m_next)
+                       plen += m->m_len;
+               t->m_pkthdr.len = plen;
+       }
+       return ((struct ip *)ip);
+
+dropfrag:
+       ipstat.ips_fragdropped++;
+       m_freem(m);
+       return (0);
+}
+
+/*
+ * Free a fragment reassembly header and all
+ * associated datagrams.
+ */
+ip_freef(fp)
+       struct ipq *fp;
+{
+       register struct ipasfrag *q, *p;
+
+       for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
+               p = q->ipf_next;
+               ip_deq(q);
+               m_freem(dtom(q));
+       }
+       remque(fp);
+       (void) m_free(dtom(fp));
+}
+
+/*
+ * Put an ip fragment on a reassembly chain.
+ * Like insque, but pointers in middle of structure.
+ */
+ip_enq(p, prev)
+       register struct ipasfrag *p, *prev;
+{
+
+       p->ipf_prev = prev;
+       p->ipf_next = prev->ipf_next;
+       prev->ipf_next->ipf_prev = p;
+       prev->ipf_next = p;
+}
+
+/*
+ * To ip_enq as remque is to insque.
+ */
+ip_deq(p)
+       register struct ipasfrag *p;
+{
+
+       p->ipf_prev->ipf_next = p->ipf_next;
+       p->ipf_next->ipf_prev = p->ipf_prev;
+}
+
+/*
+ * IP timer processing;
+ * if a timer expires on a reassembly
+ * queue, discard it.
+ */
+ip_slowtimo()
+{
+       register struct ipq *fp;
+       int s = splnet();
+
+       fp = ipq.next;
+       if (fp == 0) {
+               splx(s);
+               return;
+       }
+       while (fp != &ipq) {
+               --fp->ipq_ttl;
+               fp = fp->next;
+               if (fp->prev->ipq_ttl == 0) {
+                       ipstat.ips_fragtimeout++;
+                       ip_freef(fp->prev);
+               }
+       }
+       splx(s);
+}
+
+/*
+ * Drain off all datagram fragments.
+ */
+ip_drain()
+{
+
+       while (ipq.next != &ipq) {
+               ipstat.ips_fragdropped++;
+               ip_freef(ipq.next);
+       }
+}
+
+extern struct in_ifaddr *ifptoia();
+struct in_ifaddr *ip_rtaddr();
+
+/*
+ * Do option processing on a datagram,
+ * possibly discarding it if bad options are encountered,
+ * or forwarding it if source-routed.
+ * Returns 1 if packet has been forwarded/freed,
+ * 0 if the packet should be processed further.
+ */
+ip_dooptions(m)
+       struct mbuf *m;
+{
+       register struct ip *ip = mtod(m, struct ip *);
+       register u_char *cp;
+       register struct ip_timestamp *ipt;
+       register struct in_ifaddr *ia;
+       int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
+       struct in_addr *sin;
+       n_time ntime;
+
+       cp = (u_char *)(ip + 1);
+       cnt = (ip->ip_hl << 2) - sizeof (struct ip);
+       for (; cnt > 0; cnt -= optlen, cp += optlen) {
+               opt = cp[IPOPT_OPTVAL];
+               if (opt == IPOPT_EOL)
+                       break;
+               if (opt == IPOPT_NOP)
+                       optlen = 1;
+               else {
+                       optlen = cp[IPOPT_OLEN];
+                       if (optlen <= 0 || optlen > cnt) {
+                               code = &cp[IPOPT_OLEN] - (u_char *)ip;
+                               goto bad;
+                       }
+               }
+               switch (opt) {
+
+               default:
+                       break;
+
+               /*
+                * Source routing with record.
+                * Find interface with current destination address.
+                * If none on this machine then drop if strictly routed,
+                * or do nothing if loosely routed.
+                * Record interface address and bring up next address
+                * component.  If strictly routed make sure next
+                * address is on directly accessible net.
+                */
+               case IPOPT_LSRR:
+               case IPOPT_SSRR:
+                       if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
+                               code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+                               goto bad;
+                       }
+                       ipaddr.sin_addr = ip->ip_dst;
+                       ia = (struct in_ifaddr *)
+                               ifa_ifwithaddr((struct sockaddr *)&ipaddr);
+                       if (ia == 0) {
+                               if (opt == IPOPT_SSRR) {
+                                       type = ICMP_UNREACH;
+                                       code = ICMP_UNREACH_SRCFAIL;
+                                       goto bad;
+                               }
+                               /*
+                                * Loose routing, and not at next destination
+                                * yet; nothing to do except forward.
+                                */
+                               break;
+                       }
+                       off--;                  /* 0 origin */
+                       if (off > optlen - sizeof(struct in_addr)) {
+                               /*
+                                * End of source route.  Should be for us.
+                                */
+                               save_rte(cp, ip->ip_src);
+                               break;
+                       }
+                       /*
+                        * locate outgoing interface
+                        */
+                       bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
+                           sizeof(ipaddr.sin_addr));
+                       if (opt == IPOPT_SSRR) {
+#define        INA     struct in_ifaddr *
+#define        SA      struct sockaddr *
+                           if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
+                               ia = in_iaonnetof(in_netof(ipaddr.sin_addr));
+                       } else
+                               ia = ip_rtaddr(ipaddr.sin_addr);
+                       if (ia == 0) {
+                               type = ICMP_UNREACH;
+                               code = ICMP_UNREACH_SRCFAIL;
+                               goto bad;
+                       }
+                       ip->ip_dst = ipaddr.sin_addr;
+                       bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
+                           (caddr_t)(cp + off), sizeof(struct in_addr));
+                       cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+                       forward = 1;
+                       break;
+
+               case IPOPT_RR:
+                       if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
+                               code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+                               goto bad;
+                       }
+                       /*
+                        * If no space remains, ignore.
+                        */
+                       off--;                  /* 0 origin */
+                       if (off > optlen - sizeof(struct in_addr))
+                               break;
+                       bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
+                           sizeof(ipaddr.sin_addr));
+                       /*
+                        * locate outgoing interface; if we're the destination,
+                        * use the incoming interface (should be same).
+                        */
+                       if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
+                           (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
+                               type = ICMP_UNREACH;
+                               code = ICMP_UNREACH_HOST;
+                               goto bad;
+                       }
+                       bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
+                           (caddr_t)(cp + off), sizeof(struct in_addr));
+                       cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+                       break;
+
+               case IPOPT_TS:
+                       code = cp - (u_char *)ip;
+                       ipt = (struct ip_timestamp *)cp;
+                       if (ipt->ipt_len < 5)
+                               goto bad;
+                       if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
+                               if (++ipt->ipt_oflw == 0)
+                                       goto bad;
+                               break;
+                       }
+                       sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
+                       switch (ipt->ipt_flg) {
+
+                       case IPOPT_TS_TSONLY:
+                               break;
+
+                       case IPOPT_TS_TSANDADDR:
+                               if (ipt->ipt_ptr + sizeof(n_time) +
+                                   sizeof(struct in_addr) > ipt->ipt_len)
+                                       goto bad;
+                               ia = ifptoia(m->m_pkthdr.rcvif);
+                               bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
+                                   (caddr_t)sin, sizeof(struct in_addr));
+                               ipt->ipt_ptr += sizeof(struct in_addr);
+                               break;
+
+                       case IPOPT_TS_PRESPEC:
+                               if (ipt->ipt_ptr + sizeof(n_time) +
+                                   sizeof(struct in_addr) > ipt->ipt_len)
+                                       goto bad;
+                               bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
+                                   sizeof(struct in_addr));
+                               if (ifa_ifwithaddr((SA)&ipaddr) == 0)
+                                       continue;
+                               ipt->ipt_ptr += sizeof(struct in_addr);
+                               break;
+
+                       default:
+                               goto bad;
+                       }
+                       ntime = iptime();
+                       bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
+                           sizeof(n_time));
+                       ipt->ipt_ptr += sizeof(n_time);
+               }
+       }
+       if (forward) {
+               ip_forward(m, 1);
+               return (1);
+       } else
+               return (0);
+bad:
+       icmp_error(m, type, code);
+       return (1);
+}
+
+/*
+ * Given address of next destination (final or next hop),
+ * return internet address info of interface to be used to get there.
+ */
+struct in_ifaddr *
+ip_rtaddr(dst)
+        struct in_addr dst;
+{
+       register struct sockaddr_in *sin;
+
+       sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
+
+       if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
+               if (ipforward_rt.ro_rt) {
+                       RTFREE(ipforward_rt.ro_rt);
+                       ipforward_rt.ro_rt = 0;
+               }
+               sin->sin_family = AF_INET;
+               sin->sin_len = sizeof(*sin);
+               sin->sin_addr = dst;
+
+               rtalloc(&ipforward_rt);
+       }
+       if (ipforward_rt.ro_rt == 0)
+               return ((struct in_ifaddr *)0);
+       return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);
+}
+
+/*
+ * Save incoming source route for use in replies,
+ * to be picked up later by ip_srcroute if the receiver is interested.
+ */
+save_rte(option, dst)
+       u_char *option;
+       struct in_addr dst;
+{
+       unsigned olen;
+
+       olen = option[IPOPT_OLEN];
+#ifdef DIAGNOSTIC
+       if (ipprintfs)
+               printf("save_rte: olen %d\n", olen);
+#endif
+       if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
+               return;
+       bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen);
+       ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
+       ip_srcrt.dst = dst;
+}
+
+/*
+ * Retrieve incoming source route for use in replies,
+ * in the same form used by setsockopt.
+ * The first hop is placed before the options, will be removed later.
+ */
+struct mbuf *
+ip_srcroute()
+{
+       register struct in_addr *p, *q;
+       register struct mbuf *m;
+
+       if (ip_nhops == 0)
+               return ((struct mbuf *)0);
+       m = m_get(M_DONTWAIT, MT_SOOPTS);
+       if (m == 0)
+               return ((struct mbuf *)0);
+
+#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
+
+       /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
+       m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
+           OPTSIZ;
+#ifdef DIAGNOSTIC
+       if (ipprintfs)
+               printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
+#endif
+
+       /*
+        * First save first hop for return route
+        */
+       p = &ip_srcrt.route[ip_nhops - 1];
+       *(mtod(m, struct in_addr *)) = *p--;
+#ifdef DIAGNOSTIC
+       if (ipprintfs)
+               printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr));
+#endif
+
+       /*
+        * Copy option fields and padding (nop) to mbuf.
+        */
+       ip_srcrt.nop = IPOPT_NOP;
+       ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
+       bcopy((caddr_t)&ip_srcrt.nop,
+           mtod(m, caddr_t) + sizeof(struct in_addr), OPTSIZ);
+       q = (struct in_addr *)(mtod(m, caddr_t) +
+           sizeof(struct in_addr) + OPTSIZ);
+#undef OPTSIZ
+       /*
+        * Record return path as an IP source route,
+        * reversing the path (pointers are now aligned).
+        */
+       while (p >= ip_srcrt.route) {
+#ifdef DIAGNOSTIC
+               if (ipprintfs)
+                       printf(" %lx", ntohl(q->s_addr));
+#endif
+               *q++ = *p--;
+       }
+       /*
+        * Last hop goes to final destination.
+        */
+       *q = ip_srcrt.dst;
+#ifdef DIAGNOSTIC
+       if (ipprintfs)
+               printf(" %lx\n", ntohl(q->s_addr));
+#endif
+       return (m);
+}
+
+/*
+ * Strip out IP options, at higher
+ * level protocol in the kernel.
+ * Second argument is buffer to which options
+ * will be moved, and return value is their length.
+ * XXX should be deleted; last arg currently ignored.
+ */
+ip_stripoptions(m, mopt)
+       register struct mbuf *m;
+       struct mbuf *mopt;
+{
+       register int i;
+       struct ip *ip = mtod(m, struct ip *);
+       register caddr_t opts;
+       int olen;
+
+       olen = (ip->ip_hl<<2) - sizeof (struct ip);
+       opts = (caddr_t)(ip + 1);
+       i = m->m_len - (sizeof (struct ip) + olen);
+       bcopy(opts  + olen, opts, (unsigned)i);
+       m->m_len -= olen;
+       if (m->m_flags & M_PKTHDR)
+               m->m_pkthdr.len -= olen;
+       ip->ip_hl = sizeof(struct ip) >> 2;
+}
+
+u_char inetctlerrmap[PRC_NCMDS] = {
+       0,              0,              0,              0,
+       0,              EMSGSIZE,       EHOSTDOWN,      EHOSTUNREACH,
+       EHOSTUNREACH,   EHOSTUNREACH,   ECONNREFUSED,   ECONNREFUSED,
+       EMSGSIZE,       EHOSTUNREACH,   0,              0,
+       0,              0,              0,              0,
+       ENOPROTOOPT
+};
+
+/*
+ * Forward a packet.  If some error occurs return the sender
+ * an icmp packet.  Note we can't always generate a meaningful
+ * icmp message because icmp doesn't have a large enough repertoire
+ * of codes and types.
+ *
+ * If not forwarding, just drop the packet.  This could be confusing
+ * if ipforwarding was zero but some routing protocol was advancing
+ * us as a gateway to somewhere.  However, we must let the routing
+ * protocol deal with that.
+ *
+ * The srcrt parameter indicates whether the packet is being forwarded
+ * via a source route.
+ */
+ip_forward(m, srcrt)
+       struct mbuf *m;
+       int srcrt;
+{
+       register struct ip *ip = mtod(m, struct ip *);
+       register struct sockaddr_in *sin;
+       register struct rtentry *rt;
+       int error, type = 0, code;
+       struct mbuf *mcopy;
+       struct in_addr dest;
+
+       dest.s_addr = 0;
+#ifdef DIAGNOSTIC
+       if (ipprintfs)
+               printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
+                       ip->ip_dst, ip->ip_ttl);
+#endif
+       if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) {
+               ipstat.ips_cantforward++;
+               m_freem(m);
+               return;
+       }
+       HTONS(ip->ip_id);
+       if (ip->ip_ttl <= IPTTLDEC) {
+               icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest);
+               return;
+       }
+       ip->ip_ttl -= IPTTLDEC;
+
+       sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
+       if ((rt = ipforward_rt.ro_rt) == 0 ||
+           ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
+               if (ipforward_rt.ro_rt) {
+                       RTFREE(ipforward_rt.ro_rt);
+                       ipforward_rt.ro_rt = 0;
+               }
+               sin->sin_family = AF_INET;
+               sin->sin_len = sizeof(*sin);
+               sin->sin_addr = ip->ip_dst;
+
+               rtalloc(&ipforward_rt);
+               if (ipforward_rt.ro_rt == 0) {
+                       icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest);
+                       return;
+               }
+               rt = ipforward_rt.ro_rt;
+       }
+
+       /*
+        * Save at most 64 bytes of the packet in case
+        * we need to generate an ICMP message to the src.
+        */
+       mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64));
+
+#ifdef GATEWAY
+       ip_ifmatrix[rt->rt_ifp->if_index +
+            if_index * m->m_pkthdr.rcvif->if_index]++;
+#endif
+       /*
+        * If forwarding packet using same interface that it came in on,
+        * perhaps should send a redirect to sender to shortcut a hop.
+        * Only send redirect if source is sending directly to us,
+        * and if packet was not source routed (or has any options).
+        * Also, don't send redirect if forwarding using a default route
+        * or a route modified by a redirect.
+        */
+#define        satosin(sa)     ((struct sockaddr_in *)(sa))
+       if (rt->rt_ifp == m->m_pkthdr.rcvif &&
+           (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
+           satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
+           ipsendredirects && !srcrt) {
+               struct in_ifaddr *ia;
+               u_long src = ntohl(ip->ip_src.s_addr);
+               u_long dst = ntohl(ip->ip_dst.s_addr);
+
+               if ((ia = ifptoia(m->m_pkthdr.rcvif)) &&
+                  (src & ia->ia_subnetmask) == ia->ia_subnet) {
+                   if (rt->rt_flags & RTF_GATEWAY)
+                       dest = satosin(rt->rt_gateway)->sin_addr;
+                   else
+                       dest = ip->ip_dst;
+                   /*
+                    * If the destination is reached by a route to host,
+                    * is on a subnet of a local net, or is directly
+                    * on the attached net (!), use host redirect.
+                    * (We may be the correct first hop for other subnets.)
+                    */
+#define        RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
+                   type = ICMP_REDIRECT;
+                   if ((rt->rt_flags & RTF_HOST) ||
+                       (rt->rt_flags & RTF_GATEWAY) == 0)
+                           code = ICMP_REDIRECT_HOST;
+                   else if (RTA(rt)->ia_subnetmask != RTA(rt)->ia_netmask &&
+                       (dst & RTA(rt)->ia_netmask) ==  RTA(rt)->ia_net)
+                           code = ICMP_REDIRECT_HOST;
+                   else
+                           code = ICMP_REDIRECT_NET;
+#ifdef DIAGNOSTIC
+                   if (ipprintfs)
+                       printf("redirect (%d) to %x\n", code, dest.s_addr);
+#endif
+               }
+       }
+
+       error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING);
+       if (error)
+               ipstat.ips_cantforward++;
+       else {
+               ipstat.ips_forward++;
+               if (type)
+                       ipstat.ips_redirectsent++;
+               else {
+                       if (mcopy)
+                               m_freem(mcopy);
+                       return;
+               }
+       }
+       if (mcopy == NULL)
+               return;
+       switch (error) {
+
+       case 0:                         /* forwarded, but need redirect */
+               /* type, code set above */
+               break;
+
+       case ENETUNREACH:               /* shouldn't happen, checked above */
+       case EHOSTUNREACH:
+       case ENETDOWN:
+       case EHOSTDOWN:
+       default:
+               type = ICMP_UNREACH;
+               code = ICMP_UNREACH_HOST;
+               break;
+
+       case EMSGSIZE:
+               type = ICMP_UNREACH;
+               code = ICMP_UNREACH_NEEDFRAG;
+               ipstat.ips_cantfrag++;
+               break;
+
+       case ENOBUFS:
+               type = ICMP_SOURCEQUENCH;
+               code = 0;
+               break;
+       }
+       icmp_error(mcopy, type, code, dest);
+}
diff --git a/usr/src/sys.386bsd/netinet/ip_output.c b/usr/src/sys.386bsd/netinet/ip_output.c
new file mode 100644 (file)
index 0000000..58dbb05
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ip_output.c 7.23 (Berkeley) 11/12/90
+ */
+
+#include "param.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "errno.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "in_var.h"
+#include "ip_var.h"
+
+#ifdef vax
+#include "machine/mtpr.h"
+#endif
+
+struct mbuf *ip_insertoptions();
+
+/*
+ * IP output.  The packet in mbuf chain m contains a skeletal IP
+ * header (with len, off, ttl, proto, tos, src, dst).
+ * The mbuf chain containing the packet will be freed.
+ * The mbuf opt, if present, will not be freed.
+ */
+ip_output(m0, opt, ro, flags)
+       struct mbuf *m0;
+       struct mbuf *opt;
+       struct route *ro;
+       int flags;
+{
+       register struct ip *ip, *mhip;
+       register struct ifnet *ifp;
+       register struct mbuf *m = m0;
+       register int hlen = sizeof (struct ip);
+       int len, off, error = 0;
+       struct route iproute;
+       struct sockaddr_in *dst;
+       struct in_ifaddr *ia;
+
+#ifdef DIAGNOSTIC
+       if ((m->m_flags & M_PKTHDR) == 0)
+               panic("ip_output no HDR");
+#endif
+       if (opt) {
+               m = ip_insertoptions(m, opt, &len);
+               hlen = len;
+       }
+       ip = mtod(m, struct ip *);
+       /*
+        * Fill in IP header.
+        */
+       if ((flags & IP_FORWARDING) == 0) {
+               ip->ip_v = IPVERSION;
+               ip->ip_off &= IP_DF;
+               ip->ip_id = htons(ip_id++);
+               ip->ip_hl = hlen >> 2;
+       } else {
+               hlen = ip->ip_hl << 2;
+               ipstat.ips_localout++;
+       }
+       /*
+        * Route packet.
+        */
+       if (ro == 0) {
+               ro = &iproute;
+               bzero((caddr_t)ro, sizeof (*ro));
+       }
+       dst = (struct sockaddr_in *)&ro->ro_dst;
+       /*
+        * If there is a cached route,
+        * check that it is to the same destination
+        * and is still up.  If not, free it and try again.
+        */
+       if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+          dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
+               RTFREE(ro->ro_rt);
+               ro->ro_rt = (struct rtentry *)0;
+       }
+       if (ro->ro_rt == 0) {
+               dst->sin_family = AF_INET;
+               dst->sin_len = sizeof(*dst);
+               dst->sin_addr = ip->ip_dst;
+       }
+       /*
+        * If routing to interface only,
+        * short circuit routing lookup.
+        */
+       if (flags & IP_ROUTETOIF) {
+
+               ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
+               if (ia == 0)
+                       ia = in_iaonnetof(in_netof(ip->ip_dst));
+               if (ia == 0) {
+                       error = ENETUNREACH;
+                       goto bad;
+               }
+               ifp = ia->ia_ifp;
+       } else {
+               if (ro->ro_rt == 0)
+                       rtalloc(ro);
+               if (ro->ro_rt == 0) {
+                       error = EHOSTUNREACH;
+                       goto bad;
+               }
+               ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa;
+               ifp = ro->ro_rt->rt_ifp;
+               ro->ro_rt->rt_use++;
+               if (ro->ro_rt->rt_flags & RTF_GATEWAY)
+                       dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
+       }
+#ifndef notdef
+       /*
+        * If source address not specified yet, use address
+        * of outgoing interface.
+        */
+       if (ip->ip_src.s_addr == INADDR_ANY)
+               ip->ip_src = IA_SIN(ia)->sin_addr;
+#endif
+       /*
+        * Look for broadcast address and
+        * and verify user is allowed to send
+        * such a packet.
+        */
+       if (in_broadcast(dst->sin_addr)) {
+               if ((ifp->if_flags & IFF_BROADCAST) == 0) {
+                       error = EADDRNOTAVAIL;
+                       goto bad;
+               }
+               if ((flags & IP_ALLOWBROADCAST) == 0) {
+                       error = EACCES;
+                       goto bad;
+               }
+               /* don't allow broadcast messages to be fragmented */
+               if ((u_short)ip->ip_len > ifp->if_mtu) {
+                       error = EMSGSIZE;
+                       goto bad;
+               }
+               m->m_flags |= M_BCAST;
+       }
+
+       /*
+        * If small enough for interface, can just send directly.
+        */
+       if ((u_short)ip->ip_len <= ifp->if_mtu) {
+               ip->ip_len = htons((u_short)ip->ip_len);
+               ip->ip_off = htons((u_short)ip->ip_off);
+               ip->ip_sum = 0;
+               ip->ip_sum = in_cksum(m, hlen);
+               error = (*ifp->if_output)(ifp, m,
+                               (struct sockaddr *)dst, ro->ro_rt);
+               goto done;
+       }
+       ipstat.ips_fragmented++;
+       /*
+        * Too large for interface; fragment if possible.
+        * Must be able to put at least 8 bytes per fragment.
+        */
+       if (ip->ip_off & IP_DF) {
+               error = EMSGSIZE;
+               goto bad;
+       }
+       len = (ifp->if_mtu - hlen) &~ 7;
+       if (len < 8) {
+               error = EMSGSIZE;
+               goto bad;
+       }
+
+    {
+       int mhlen, firstlen = len;
+       struct mbuf **mnext = &m->m_nextpkt;
+
+       /*
+        * Loop through length of segment after first fragment,
+        * make new header and copy data of each part and link onto chain.
+        */
+       m0 = m;
+       mhlen = sizeof (struct ip);
+       for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
+               MGETHDR(m, M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       error = ENOBUFS;
+                       goto sendorfree;
+               }
+               m->m_data += max_linkhdr;
+               mhip = mtod(m, struct ip *);
+               *mhip = *ip;
+               if (hlen > sizeof (struct ip)) {
+                       mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
+                       mhip->ip_hl = mhlen >> 2;
+               }
+               m->m_len = mhlen;
+               mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
+               if (ip->ip_off & IP_MF)
+                       mhip->ip_off |= IP_MF;
+               if (off + len >= (u_short)ip->ip_len)
+                       len = (u_short)ip->ip_len - off;
+               else
+                       mhip->ip_off |= IP_MF;
+               mhip->ip_len = htons((u_short)(len + mhlen));
+               m->m_next = m_copy(m0, off, len);
+               if (m->m_next == 0) {
+                       error = ENOBUFS;        /* ??? */
+                       goto sendorfree;
+               }
+               m->m_pkthdr.len = mhlen + len;
+               m->m_pkthdr.rcvif = (struct ifnet *)0;
+               mhip->ip_off = htons((u_short)mhip->ip_off);
+               mhip->ip_sum = 0;
+               mhip->ip_sum = in_cksum(m, mhlen);
+               *mnext = m;
+               mnext = &m->m_nextpkt;
+               ipstat.ips_ofragments++;
+       }
+       /*
+        * Update first fragment by trimming what's been copied out
+        * and updating header, then send each fragment (in order).
+        */
+       m = m0;
+       m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
+       m->m_pkthdr.len = hlen + firstlen;
+       ip->ip_len = htons((u_short)m->m_pkthdr.len);
+       ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
+       ip->ip_sum = 0;
+       ip->ip_sum = in_cksum(m, hlen);
+sendorfree:
+       for (m = m0; m; m = m0) {
+               m0 = m->m_nextpkt;
+               m->m_nextpkt = 0;
+               if (error == 0)
+                       error = (*ifp->if_output)(ifp, m,
+                           (struct sockaddr *)dst, ro->ro_rt);
+               else
+                       m_freem(m);
+       }
+    }
+done:
+       if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
+               RTFREE(ro->ro_rt);
+       return (error);
+bad:
+       m_freem(m0);
+       goto done;
+}
+
+/*
+ * Insert IP options into preformed packet.
+ * Adjust IP destination as required for IP source routing,
+ * as indicated by a non-zero in_addr at the start of the options.
+ */
+struct mbuf *
+ip_insertoptions(m, opt, phlen)
+       register struct mbuf *m;
+       struct mbuf *opt;
+       int *phlen;
+{
+       register struct ipoption *p = mtod(opt, struct ipoption *);
+       struct mbuf *n;
+       register struct ip *ip = mtod(m, struct ip *);
+       unsigned optlen;
+
+       optlen = opt->m_len - sizeof(p->ipopt_dst);
+       if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
+               return (m);             /* XXX should fail */
+       if (p->ipopt_dst.s_addr)
+               ip->ip_dst = p->ipopt_dst;
+       if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
+               MGETHDR(n, M_DONTWAIT, MT_HEADER);
+               if (n == 0)
+                       return (m);
+               n->m_pkthdr.len = m->m_pkthdr.len + optlen;
+               m->m_len -= sizeof(struct ip);
+               m->m_data += sizeof(struct ip);
+               n->m_next = m;
+               m = n;
+               m->m_len = optlen + sizeof(struct ip);
+               m->m_data += max_linkhdr;
+               bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
+       } else {
+               m->m_data -= optlen;
+               m->m_len += optlen;
+               m->m_pkthdr.len += optlen;
+               ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
+       }
+       ip = mtod(m, struct ip *);
+       bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
+       *phlen = sizeof(struct ip) + optlen;
+       ip->ip_len += optlen;
+       return (m);
+}
+
+/*
+ * Copy options from ip to jp,
+ * omitting those not copied during fragmentation.
+ */
+ip_optcopy(ip, jp)
+       struct ip *ip, *jp;
+{
+       register u_char *cp, *dp;
+       int opt, optlen, cnt;
+
+       cp = (u_char *)(ip + 1);
+       dp = (u_char *)(jp + 1);
+       cnt = (ip->ip_hl << 2) - sizeof (struct ip);
+       for (; cnt > 0; cnt -= optlen, cp += optlen) {
+               opt = cp[0];
+               if (opt == IPOPT_EOL)
+                       break;
+               if (opt == IPOPT_NOP)
+                       optlen = 1;
+               else
+                       optlen = cp[IPOPT_OLEN];
+               /* bogus lengths should have been caught by ip_dooptions */
+               if (optlen > cnt)
+                       optlen = cnt;
+               if (IPOPT_COPIED(opt)) {
+                       bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
+                       dp += optlen;
+               }
+       }
+       for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
+               *dp++ = IPOPT_EOL;
+       return (optlen);
+}
+
+/*
+ * IP socket option processing.
+ */
+ip_ctloutput(op, so, level, optname, mp)
+       int op;
+       struct socket *so;
+       int level, optname;
+       struct mbuf **mp;
+{
+       register struct inpcb *inp = sotoinpcb(so);
+       register struct mbuf *m = *mp;
+       register int optval;
+       int error = 0;
+
+       if (level != IPPROTO_IP)
+               error = EINVAL;
+       else switch (op) {
+
+       case PRCO_SETOPT:
+               switch (optname) {
+               case IP_OPTIONS:
+#ifdef notyet
+               case IP_RETOPTS:
+                       return (ip_pcbopts(optname, &inp->inp_options, m));
+#else
+                       return (ip_pcbopts(&inp->inp_options, m));
+#endif
+
+               case IP_TOS:
+               case IP_TTL:
+               case IP_RECVOPTS:
+               case IP_RECVRETOPTS:
+               case IP_RECVDSTADDR:
+                       if (m->m_len != sizeof(int))
+                               error = EINVAL;
+                       else {
+                               optval = *mtod(m, int *);
+                               switch (optname) {
+
+                               case IP_TOS:
+                                       inp->inp_ip.ip_tos = optval;
+                                       break;
+
+                               case IP_TTL:
+                                       inp->inp_ip.ip_ttl = optval;
+                                       break;
+#define        OPTSET(bit) \
+       if (optval) \
+               inp->inp_flags |= bit; \
+       else \
+               inp->inp_flags &= ~bit;
+
+                               case IP_RECVOPTS:
+                                       OPTSET(INP_RECVOPTS);
+                                       break;
+
+                               case IP_RECVRETOPTS:
+                                       OPTSET(INP_RECVRETOPTS);
+                                       break;
+
+                               case IP_RECVDSTADDR:
+                                       OPTSET(INP_RECVDSTADDR);
+                                       break;
+                               }
+                       }
+                       break;
+#undef OPTSET
+
+               default:
+                       error = EINVAL;
+                       break;
+               }
+               if (m)
+                       (void)m_free(m);
+               break;
+
+       case PRCO_GETOPT:
+               switch (optname) {
+               case IP_OPTIONS:
+               case IP_RETOPTS:
+                       *mp = m = m_get(M_WAIT, MT_SOOPTS);
+                       if (inp->inp_options) {
+                               m->m_len = inp->inp_options->m_len;
+                               bcopy(mtod(inp->inp_options, caddr_t),
+                                   mtod(m, caddr_t), (unsigned)m->m_len);
+                       } else
+                               m->m_len = 0;
+                       break;
+
+               case IP_TOS:
+               case IP_TTL:
+               case IP_RECVOPTS:
+               case IP_RECVRETOPTS:
+               case IP_RECVDSTADDR:
+                       *mp = m = m_get(M_WAIT, MT_SOOPTS);
+                       m->m_len = sizeof(int);
+                       switch (optname) {
+
+                       case IP_TOS:
+                               optval = inp->inp_ip.ip_tos;
+                               break;
+
+                       case IP_TTL:
+                               optval = inp->inp_ip.ip_ttl;
+                               break;
+
+#define        OPTBIT(bit)     (inp->inp_flags & bit ? 1 : 0)
+
+                       case IP_RECVOPTS:
+                               optval = OPTBIT(INP_RECVOPTS);
+                               break;
+
+                       case IP_RECVRETOPTS:
+                               optval = OPTBIT(INP_RECVRETOPTS);
+                               break;
+
+                       case IP_RECVDSTADDR:
+                               optval = OPTBIT(INP_RECVDSTADDR);
+                               break;
+                       }
+                       *mtod(m, int *) = optval;
+                       break;
+
+               default:
+                       error = EINVAL;
+                       break;
+               }
+               break;
+       }
+       return (error);
+}
+
+/*
+ * Set up IP options in pcb for insertion in output packets.
+ * Store in mbuf with pointer in pcbopt, adding pseudo-option
+ * with destination address if source routed.
+ */
+#ifdef notyet
+ip_pcbopts(optname, pcbopt, m)
+       int optname;
+#else
+ip_pcbopts(pcbopt, m)
+#endif
+       struct mbuf **pcbopt;
+       register struct mbuf *m;
+{
+       register cnt, optlen;
+       register u_char *cp;
+       u_char opt;
+
+       /* turn off any old options */
+       if (*pcbopt)
+               (void)m_free(*pcbopt);
+       *pcbopt = 0;
+       if (m == (struct mbuf *)0 || m->m_len == 0) {
+               /*
+                * Only turning off any previous options.
+                */
+               if (m)
+                       (void)m_free(m);
+               return (0);
+       }
+
+#ifndef        vax
+       if (m->m_len % sizeof(long))
+               goto bad;
+#endif
+       /*
+        * IP first-hop destination address will be stored before
+        * actual options; move other options back
+        * and clear it when none present.
+        */
+       if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
+               goto bad;
+       cnt = m->m_len;
+       m->m_len += sizeof(struct in_addr);
+       cp = mtod(m, u_char *) + sizeof(struct in_addr);
+       ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
+       bzero(mtod(m, caddr_t), sizeof(struct in_addr));
+
+       for (; cnt > 0; cnt -= optlen, cp += optlen) {
+               opt = cp[IPOPT_OPTVAL];
+               if (opt == IPOPT_EOL)
+                       break;
+               if (opt == IPOPT_NOP)
+                       optlen = 1;
+               else {
+                       optlen = cp[IPOPT_OLEN];
+                       if (optlen <= IPOPT_OLEN || optlen > cnt)
+                               goto bad;
+               }
+               switch (opt) {
+
+               default:
+                       break;
+
+               case IPOPT_LSRR:
+               case IPOPT_SSRR:
+                       /*
+                        * user process specifies route as:
+                        *      ->A->B->C->D
+                        * D must be our final destination (but we can't
+                        * check that since we may not have connected yet).
+                        * A is first hop destination, which doesn't appear in
+                        * actual IP option, but is stored before the options.
+                        */
+                       if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
+                               goto bad;
+                       m->m_len -= sizeof(struct in_addr);
+                       cnt -= sizeof(struct in_addr);
+                       optlen -= sizeof(struct in_addr);
+                       cp[IPOPT_OLEN] = optlen;
+                       /*
+                        * Move first hop before start of options.
+                        */
+                       bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
+                           sizeof(struct in_addr));
+                       /*
+                        * Then copy rest of options back
+                        * to close up the deleted entry.
+                        */
+                       ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
+                           sizeof(struct in_addr)),
+                           (caddr_t)&cp[IPOPT_OFFSET+1],
+                           (unsigned)cnt + sizeof(struct in_addr));
+                       break;
+               }
+       }
+       if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
+               goto bad;
+       *pcbopt = m;
+       return (0);
+
+bad:
+       (void)m_free(m);
+       return (EINVAL);
+}
diff --git a/usr/src/sys.386bsd/netinet/ip_var.h b/usr/src/sys.386bsd/netinet/ip_var.h
new file mode 100644 (file)
index 0000000..f654393
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ip_var.h    7.7 (Berkeley) 6/28/90
+ */
+
+/*
+ * Overlay for ip header used by other protocols (tcp, udp).
+ */
+struct ipovly {
+       caddr_t ih_next, ih_prev;       /* for protocol sequence q's */
+       u_char  ih_x1;                  /* (unused) */
+       u_char  ih_pr;                  /* protocol */
+       short   ih_len;                 /* protocol length */
+       struct  in_addr ih_src;         /* source internet address */
+       struct  in_addr ih_dst;         /* destination internet address */
+};
+
+/*
+ * Ip reassembly queue structure.  Each fragment
+ * being reassembled is attached to one of these structures.
+ * They are timed out after ipq_ttl drops to 0, and may also
+ * be reclaimed if memory becomes tight.
+ */
+struct ipq {
+       struct  ipq *next,*prev;        /* to other reass headers */
+       u_char  ipq_ttl;                /* time for reass q to live */
+       u_char  ipq_p;                  /* protocol of this fragment */
+       u_short ipq_id;                 /* sequence id for reassembly */
+       struct  ipasfrag *ipq_next,*ipq_prev;
+                                       /* to ip headers of fragments */
+       struct  in_addr ipq_src,ipq_dst;
+};
+
+/*
+ * Ip header, when holding a fragment.
+ *
+ * Note: ipf_next must be at same offset as ipq_next above
+ */
+struct ipasfrag {
+#if BYTE_ORDER == LITTLE_ENDIAN 
+       u_char  ip_hl:4,
+               ip_v:4;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN 
+       u_char  ip_v:4,
+               ip_hl:4;
+#endif
+       u_char  ipf_mff;                /* copied from (ip_off&IP_MF) */
+       short   ip_len;
+       u_short ip_id;
+       short   ip_off;
+       u_char  ip_ttl;
+       u_char  ip_p;
+       u_short ip_sum;
+       struct  ipasfrag *ipf_next;     /* next fragment */
+       struct  ipasfrag *ipf_prev;     /* previous fragment */
+};
+
+/*
+ * Structure stored in mbuf in inpcb.ip_options
+ * and passed to ip_output when ip options are in use.
+ * The actual length of the options (including ipopt_dst)
+ * is in m_len.
+ */
+#define MAX_IPOPTLEN   40
+
+struct ipoption {
+       struct  in_addr ipopt_dst;      /* first-hop dst if source routed */
+       char    ipopt_list[MAX_IPOPTLEN];       /* options proper */
+};
+
+struct ipstat {
+       long    ips_total;              /* total packets received */
+       long    ips_badsum;             /* checksum bad */
+       long    ips_tooshort;           /* packet too short */
+       long    ips_toosmall;           /* not enough data */
+       long    ips_badhlen;            /* ip header length < data size */
+       long    ips_badlen;             /* ip length < ip header length */
+       long    ips_fragments;          /* fragments received */
+       long    ips_fragdropped;        /* frags dropped (dups, out of space) */
+       long    ips_fragtimeout;        /* fragments timed out */
+       long    ips_forward;            /* packets forwarded */
+       long    ips_cantforward;        /* packets rcvd for unreachable dest */
+       long    ips_redirectsent;       /* packets forwarded on same net */
+       long    ips_noproto;            /* unknown or unsupported protocol */
+       long    ips_delivered;          /* packets consumed here */
+       long    ips_localout;           /* total ip packets generated here */
+       long    ips_odropped;           /* lost packets due to nobufs, etc. */
+       long    ips_reassembled;        /* total packets reassembled ok */
+       long    ips_fragmented;         /* output packets fragmented ok */
+       long    ips_ofragments;         /* output fragments created */
+       long    ips_cantfrag;           /* don't fragment flag was set, etc. */
+};
+
+#ifdef KERNEL
+/* flags passed to ip_output as last parameter */
+#define        IP_FORWARDING           0x1             /* most of ip header exists */
+#define        IP_ROUTETOIF            SO_DONTROUTE    /* bypass routing tables */
+#define        IP_ALLOWBROADCAST       SO_BROADCAST    /* can send broadcast packets */
+
+struct ipstat  ipstat;
+struct ipq     ipq;                    /* ip reass. queue */
+u_short        ip_id;                          /* ip packet ctr, for ids */
+
+struct mbuf *ip_srcroute();
+#endif
diff --git a/usr/src/sys.386bsd/netinet/tcp.h b/usr/src/sys.386bsd/netinet/tcp.h
new file mode 100644 (file)
index 0000000..d38f340
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp.h       7.7 (Berkeley) 6/28/90
+ */
+
+typedef        u_long  tcp_seq;
+/*
+ * TCP header.
+ * Per RFC 793, September, 1981.
+ */
+struct tcphdr {
+       u_short th_sport;               /* source port */
+       u_short th_dport;               /* destination port */
+       tcp_seq th_seq;                 /* sequence number */
+       tcp_seq th_ack;                 /* acknowledgement number */
+#if BYTE_ORDER == LITTLE_ENDIAN 
+       u_char  th_x2:4,                /* (unused) */
+               th_off:4;               /* data offset */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN 
+       u_char  th_off:4,               /* data offset */
+               th_x2:4;                /* (unused) */
+#endif
+       u_char  th_flags;
+#define        TH_FIN  0x01
+#define        TH_SYN  0x02
+#define        TH_RST  0x04
+#define        TH_PUSH 0x08
+#define        TH_ACK  0x10
+#define        TH_URG  0x20
+       u_short th_win;                 /* window */
+       u_short th_sum;                 /* checksum */
+       u_short th_urp;                 /* urgent pointer */
+};
+
+#define        TCPOPT_EOL      0
+#define        TCPOPT_NOP      1
+#define        TCPOPT_MAXSEG   2
+
+/*
+ * Default maximum segment size for TCP.
+ * With an IP MSS of 576, this is 536,
+ * but 512 is probably more convenient.
+ * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
+ */
+#define        TCP_MSS 512
+
+#define        TCP_MAXWIN      65535           /* largest value for window */
+
+/*
+ * User-settable options (used with setsockopt).
+ */
+#define        TCP_NODELAY     0x01    /* don't delay send to coalesce packets */
+#define        TCP_MAXSEG      0x02    /* set maximum segment size */
diff --git a/usr/src/sys.386bsd/netinet/tcp_debug.c b/usr/src/sys.386bsd/netinet/tcp_debug.c
new file mode 100644 (file)
index 0000000..15e0094
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_debug.c 7.6 (Berkeley) 6/28/90
+ */
+
+#ifdef TCPDEBUG
+/* load symbolic names */
+#define PRUREQUESTS
+#define TCPSTATES
+#define        TCPTIMERS
+#define        TANAMES
+#endif
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "protosw.h"
+#include "errno.h"
+
+#include "../net/route.h"
+#include "../net/if.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "ip_var.h"
+#include "tcp.h"
+#include "tcp_fsm.h"
+#include "tcp_seq.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+#include "tcp_debug.h"
+
+#ifdef TCPDEBUG
+int    tcpconsdebug = 0;
+#endif
+/*
+ * Tcp debug routines
+ */
+tcp_trace(act, ostate, tp, ti, req)
+       short act, ostate;
+       struct tcpcb *tp;
+       struct tcpiphdr *ti;
+       int req;
+{
+       tcp_seq seq, ack;
+       int len, flags;
+       struct tcp_debug *td = &tcp_debug[tcp_debx++];
+
+       if (tcp_debx == TCP_NDEBUG)
+               tcp_debx = 0;
+       td->td_time = iptime();
+       td->td_act = act;
+       td->td_ostate = ostate;
+       td->td_tcb = (caddr_t)tp;
+       if (tp)
+               td->td_cb = *tp;
+       else
+               bzero((caddr_t)&td->td_cb, sizeof (*tp));
+       if (ti)
+               td->td_ti = *ti;
+       else
+               bzero((caddr_t)&td->td_ti, sizeof (*ti));
+       td->td_req = req;
+#ifdef TCPDEBUG
+       if (tcpconsdebug == 0)
+               return;
+       if (tp)
+               printf("%x %s:", tp, tcpstates[ostate]);
+       else
+               printf("???????? ");
+       printf("%s ", tanames[act]);
+       switch (act) {
+
+       case TA_INPUT:
+       case TA_OUTPUT:
+       case TA_DROP:
+               if (ti == 0)
+                       break;
+               seq = ti->ti_seq;
+               ack = ti->ti_ack;
+               len = ti->ti_len;
+               if (act == TA_OUTPUT) {
+                       seq = ntohl(seq);
+                       ack = ntohl(ack);
+                       len = ntohs((u_short)len);
+               }
+               if (act == TA_OUTPUT)
+                       len -= sizeof (struct tcphdr);
+               if (len)
+                       printf("[%x..%x)", seq, seq+len);
+               else
+                       printf("%x", seq);
+               printf("@%x, urp=%x", ack, ti->ti_urp);
+               flags = ti->ti_flags;
+               if (flags) {
+#ifndef lint
+                       char *cp = "<";
+#define pf(f) { if (ti->ti_flags&TH_/**/f) { printf("%s%s", cp, "f"); cp = ","; } }
+                       pf(SYN); pf(ACK); pf(FIN); pf(RST); pf(PUSH); pf(URG);
+#endif
+                       printf(">");
+               }
+               break;
+
+       case TA_USER:
+               printf("%s", prurequests[req&0xff]);
+               if ((req & 0xff) == PRU_SLOWTIMO)
+                       printf("<%s>", tcptimers[req>>8]);
+               break;
+       }
+       if (tp)
+               printf(" -> %s", tcpstates[tp->t_state]);
+       /* print out internal state of tp !?! */
+       printf("\n");
+       if (tp == 0)
+               return;
+       printf("\trcv_(nxt,wnd,up) (%x,%x,%x) snd_(una,nxt,max) (%x,%x,%x)\n",
+           tp->rcv_nxt, tp->rcv_wnd, tp->rcv_up, tp->snd_una, tp->snd_nxt,
+           tp->snd_max);
+       printf("\tsnd_(wl1,wl2,wnd) (%x,%x,%x)\n",
+           tp->snd_wl1, tp->snd_wl2, tp->snd_wnd);
+#endif /* TCPDEBUG */
+}
diff --git a/usr/src/sys.386bsd/netinet/tcp_debug.h b/usr/src/sys.386bsd/netinet/tcp_debug.h
new file mode 100644 (file)
index 0000000..4e3372b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_debug.h 7.4 (Berkeley) 6/28/90
+ */
+
+struct tcp_debug {
+       n_time  td_time;
+       short   td_act;
+       short   td_ostate;
+       caddr_t td_tcb;
+       struct  tcpiphdr td_ti;
+       short   td_req;
+       struct  tcpcb td_cb;
+};
+
+#define        TA_INPUT        0
+#define        TA_OUTPUT       1
+#define        TA_USER         2
+#define        TA_RESPOND      3
+#define        TA_DROP         4
+
+#ifdef TANAMES
+char   *tanames[] =
+    { "input", "output", "user", "respond", "drop" };
+#endif
+
+#define        TCP_NDEBUG 100
+struct tcp_debug tcp_debug[TCP_NDEBUG];
+int    tcp_debx;
diff --git a/usr/src/sys.386bsd/netinet/tcp_fsm.h b/usr/src/sys.386bsd/netinet/tcp_fsm.h
new file mode 100644 (file)
index 0000000..e9280b5
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_fsm.h   7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * TCP FSM state definitions.
+ * Per RFC793, September, 1981.
+ */
+
+#define        TCP_NSTATES     11
+
+#define        TCPS_CLOSED             0       /* closed */
+#define        TCPS_LISTEN             1       /* listening for connection */
+#define        TCPS_SYN_SENT           2       /* active, have sent syn */
+#define        TCPS_SYN_RECEIVED       3       /* have send and received syn */
+/* states < TCPS_ESTABLISHED are those where connections not established */
+#define        TCPS_ESTABLISHED        4       /* established */
+#define        TCPS_CLOSE_WAIT         5       /* rcvd fin, waiting for close */
+/* states > TCPS_CLOSE_WAIT are those where user has closed */
+#define        TCPS_FIN_WAIT_1         6       /* have closed, sent fin */
+#define        TCPS_CLOSING            7       /* closed xchd FIN; await FIN ACK */
+#define        TCPS_LAST_ACK           8       /* had fin and close; await FIN ACK */
+/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
+#define        TCPS_FIN_WAIT_2         9       /* have closed, fin is acked */
+#define        TCPS_TIME_WAIT          10      /* in 2*msl quiet wait after close */
+
+#define        TCPS_HAVERCVDSYN(s)     ((s) >= TCPS_SYN_RECEIVED)
+#define        TCPS_HAVERCVDFIN(s)     ((s) >= TCPS_TIME_WAIT)
+
+#ifdef TCPOUTFLAGS
+/*
+ * Flags used when sending segments in tcp_output.
+ * Basic flags (TH_RST,TH_ACK,TH_SYN,TH_FIN) are totally
+ * determined by state, with the proviso that TH_FIN is sent only
+ * if all data queued for output is included in the segment.
+ */
+u_char tcp_outflags[TCP_NSTATES] = {
+    TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK,
+    TH_ACK, TH_ACK,
+    TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK,
+};
+#endif
+
+#ifdef KPROF
+int    tcp_acounts[TCP_NSTATES][PRU_NREQ];
+#endif
+
+#ifdef TCPSTATES
+char *tcpstates[] = {
+       "CLOSED",       "LISTEN",       "SYN_SENT",     "SYN_RCVD",
+       "ESTABLISHED",  "CLOSE_WAIT",   "FIN_WAIT_1",   "CLOSING",
+       "LAST_ACK",     "FIN_WAIT_2",   "TIME_WAIT",
+};
+#endif
diff --git a/usr/src/sys.386bsd/netinet/tcp_input.c b/usr/src/sys.386bsd/netinet/tcp_input.c
new file mode 100644 (file)
index 0000000..f6fcc06
--- /dev/null
@@ -0,0 +1,1493 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_input.c 7.25 (Berkeley) 6/30/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "errno.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "ip_var.h"
+#include "tcp.h"
+#include "tcp_fsm.h"
+#include "tcp_seq.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+#include "tcp_debug.h"
+
+int    tcprexmtthresh = 3;
+int    tcppredack;     /* XXX debugging: times hdr predict ok for acks */
+int    tcppreddat;     /* XXX # times header prediction ok for data packets */
+int    tcppcbcachemiss;
+struct tcpiphdr tcp_saveti;
+struct inpcb *tcp_last_inpcb = &tcb;
+
+struct tcpcb *tcp_newtcpcb();
+
+/*
+ * Insert segment ti into reassembly queue of tcp with
+ * control block tp.  Return TH_FIN if reassembly now includes
+ * a segment with FIN.  The macro form does the common case inline
+ * (segment is the next to be received on an established connection,
+ * and the queue is empty), avoiding linkage into and removal
+ * from the queue and repetition of various conversions.
+ * Set DELACK for segments received in order, but ack immediately
+ * when segments are out of order (so fast retransmit can work).
+ */
+#define        TCP_REASS(tp, ti, m, so, flags) { \
+       if ((ti)->ti_seq == (tp)->rcv_nxt && \
+           (tp)->seg_next == (struct tcpiphdr *)(tp) && \
+           (tp)->t_state == TCPS_ESTABLISHED) { \
+               tp->t_flags |= TF_DELACK; \
+               (tp)->rcv_nxt += (ti)->ti_len; \
+               flags = (ti)->ti_flags & TH_FIN; \
+               tcpstat.tcps_rcvpack++;\
+               tcpstat.tcps_rcvbyte += (ti)->ti_len;\
+               sbappend(&(so)->so_rcv, (m)); \
+               sorwakeup(so); \
+       } else { \
+               (flags) = tcp_reass((tp), (ti), (m)); \
+               tp->t_flags |= TF_ACKNOW; \
+       } \
+}
+
+tcp_reass(tp, ti, m)
+       register struct tcpcb *tp;
+       register struct tcpiphdr *ti;
+       struct mbuf *m;
+{
+       register struct tcpiphdr *q;
+       struct socket *so = tp->t_inpcb->inp_socket;
+       int flags;
+
+       /*
+        * Call with ti==0 after become established to
+        * force pre-ESTABLISHED data up to user socket.
+        */
+       if (ti == 0)
+               goto present;
+
+       /*
+        * Find a segment which begins after this one does.
+        */
+       for (q = tp->seg_next; q != (struct tcpiphdr *)tp;
+           q = (struct tcpiphdr *)q->ti_next)
+               if (SEQ_GT(q->ti_seq, ti->ti_seq))
+                       break;
+
+       /*
+        * If there is a preceding segment, it may provide some of
+        * our data already.  If so, drop the data from the incoming
+        * segment.  If it provides all of our data, drop us.
+        */
+       if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) {
+               register int i;
+               q = (struct tcpiphdr *)q->ti_prev;
+               /* conversion to int (in i) handles seq wraparound */
+               i = q->ti_seq + q->ti_len - ti->ti_seq;
+               if (i > 0) {
+                       if (i >= ti->ti_len) {
+                               tcpstat.tcps_rcvduppack++;
+                               tcpstat.tcps_rcvdupbyte += ti->ti_len;
+                               m_freem(m);
+                               return (0);
+                       }
+                       m_adj(m, i);
+                       ti->ti_len -= i;
+                       ti->ti_seq += i;
+               }
+               q = (struct tcpiphdr *)(q->ti_next);
+       }
+       tcpstat.tcps_rcvoopack++;
+       tcpstat.tcps_rcvoobyte += ti->ti_len;
+       REASS_MBUF(ti) = m;             /* XXX */
+
+       /*
+        * While we overlap succeeding segments trim them or,
+        * if they are completely covered, dequeue them.
+        */
+       while (q != (struct tcpiphdr *)tp) {
+               register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq;
+               if (i <= 0)
+                       break;
+               if (i < q->ti_len) {
+                       q->ti_seq += i;
+                       q->ti_len -= i;
+                       m_adj(REASS_MBUF(q), i);
+                       break;
+               }
+               q = (struct tcpiphdr *)q->ti_next;
+               m = REASS_MBUF((struct tcpiphdr *)q->ti_prev);
+               remque(q->ti_prev);
+               m_freem(m);
+       }
+
+       /*
+        * Stick new segment in its place.
+        */
+       insque(ti, q->ti_prev);
+
+present:
+       /*
+        * Present data to user, advancing rcv_nxt through
+        * completed sequence space.
+        */
+       if (TCPS_HAVERCVDSYN(tp->t_state) == 0)
+               return (0);
+       ti = tp->seg_next;
+       if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt)
+               return (0);
+       if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
+               return (0);
+       do {
+               tp->rcv_nxt += ti->ti_len;
+               flags = ti->ti_flags & TH_FIN;
+               remque(ti);
+               m = REASS_MBUF(ti);
+               ti = (struct tcpiphdr *)ti->ti_next;
+               if (so->so_state & SS_CANTRCVMORE)
+                       m_freem(m);
+               else
+                       sbappend(&so->so_rcv, m);
+       } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
+       sorwakeup(so);
+       return (flags);
+}
+
+/*
+ * TCP input routine, follows pages 65-76 of the
+ * protocol specification dated September, 1981 very closely.
+ */
+tcp_input(m, iphlen)
+       register struct mbuf *m;
+       int iphlen;
+{
+       register struct tcpiphdr *ti;
+       register struct inpcb *inp;
+       struct mbuf *om = 0;
+       int len, tlen, off;
+       register struct tcpcb *tp = 0;
+       register int tiflags;
+       struct socket *so;
+       int todrop, acked, ourfinisacked, needoutput = 0;
+       short ostate;
+       struct in_addr laddr;
+       int dropsocket = 0;
+       int iss = 0;
+
+       tcpstat.tcps_rcvtotal++;
+       /*
+        * Get IP and TCP header together in first mbuf.
+        * Note: IP leaves IP header in first mbuf.
+        */
+       ti = mtod(m, struct tcpiphdr *);
+       if (iphlen > sizeof (struct ip))
+               ip_stripoptions(m, (struct mbuf *)0);
+       if (m->m_len < sizeof (struct tcpiphdr)) {
+               if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) {
+                       tcpstat.tcps_rcvshort++;
+                       return;
+               }
+               ti = mtod(m, struct tcpiphdr *);
+       }
+
+       /*
+        * Checksum extended TCP header and data.
+        */
+       tlen = ((struct ip *)ti)->ip_len;
+       len = sizeof (struct ip) + tlen;
+       ti->ti_next = ti->ti_prev = 0;
+       ti->ti_x1 = 0;
+       ti->ti_len = (u_short)tlen;
+       HTONS(ti->ti_len);
+       if (ti->ti_sum = in_cksum(m, len)) {
+               tcpstat.tcps_rcvbadsum++;
+               goto drop;
+       }
+
+       /*
+        * Check that TCP offset makes sense,
+        * pull out TCP options and adjust length.              XXX
+        */
+       off = ti->ti_off << 2;
+       if (off < sizeof (struct tcphdr) || off > tlen) {
+               tcpstat.tcps_rcvbadoff++;
+               goto drop;
+       }
+       tlen -= off;
+       ti->ti_len = tlen;
+       if (off > sizeof (struct tcphdr)) {
+               if (m->m_len < sizeof(struct ip) + off) {
+                       if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) {
+                               tcpstat.tcps_rcvshort++;
+                               return;
+                       }
+                       ti = mtod(m, struct tcpiphdr *);
+               }
+               om = m_get(M_DONTWAIT, MT_DATA);
+               if (om == 0)
+                       goto drop;
+               om->m_len = off - sizeof (struct tcphdr);
+               { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
+                 bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len);
+                 m->m_len -= om->m_len;
+                 m->m_pkthdr.len -= om->m_len;
+                 bcopy(op+om->m_len, op,
+                  (unsigned)(m->m_len-sizeof (struct tcpiphdr)));
+               }
+       }
+       tiflags = ti->ti_flags;
+
+       /*
+        * Convert TCP protocol specific fields to host format.
+        */
+       NTOHL(ti->ti_seq);
+       NTOHL(ti->ti_ack);
+       NTOHS(ti->ti_win);
+       NTOHS(ti->ti_urp);
+
+       /*
+        * Locate pcb for segment.
+        */
+findpcb:
+       inp = tcp_last_inpcb;
+       if (inp->inp_lport != ti->ti_dport ||
+           inp->inp_fport != ti->ti_sport ||
+           inp->inp_faddr.s_addr != ti->ti_src.s_addr ||
+           inp->inp_laddr.s_addr != ti->ti_dst.s_addr) {
+               inp = in_pcblookup(&tcb, ti->ti_src, ti->ti_sport,
+                   ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD);
+               if (inp)
+                       tcp_last_inpcb = inp;
+               ++tcppcbcachemiss;
+       }
+
+       /*
+        * If the state is CLOSED (i.e., TCB does not exist) then
+        * all data in the incoming segment is discarded.
+        * If the TCB exists but is in CLOSED state, it is embryonic,
+        * but should either do a listen or a connect soon.
+        */
+       if (inp == 0)
+               goto dropwithreset;
+       tp = intotcpcb(inp);
+       if (tp == 0)
+               goto dropwithreset;
+       if (tp->t_state == TCPS_CLOSED)
+               goto drop;
+       so = inp->inp_socket;
+       if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
+               if (so->so_options & SO_DEBUG) {
+                       ostate = tp->t_state;
+                       tcp_saveti = *ti;
+               }
+               if (so->so_options & SO_ACCEPTCONN) {
+                       so = sonewconn(so, 0);
+                       if (so == 0)
+                               goto drop;
+                       /*
+                        * This is ugly, but ....
+                        *
+                        * Mark socket as temporary until we're
+                        * committed to keeping it.  The code at
+                        * ``drop'' and ``dropwithreset'' check the
+                        * flag dropsocket to see if the temporary
+                        * socket created here should be discarded.
+                        * We mark the socket as discardable until
+                        * we're committed to it below in TCPS_LISTEN.
+                        */
+                       dropsocket++;
+                       inp = (struct inpcb *)so->so_pcb;
+                       inp->inp_laddr = ti->ti_dst;
+                       inp->inp_lport = ti->ti_dport;
+#if BSD>=43
+                       inp->inp_options = ip_srcroute();
+#endif
+                       tp = intotcpcb(inp);
+                       tp->t_state = TCPS_LISTEN;
+               }
+       }
+
+       /*
+        * Segment received on connection.
+        * Reset idle time and keep-alive timer.
+        */
+       tp->t_idle = 0;
+       tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+
+       /*
+        * Process options if not in LISTEN state,
+        * else do it below (after getting remote address).
+        */
+       if (om && tp->t_state != TCPS_LISTEN) {
+               tcp_dooptions(tp, om, ti);
+               om = 0;
+       }
+       /* 
+        * Header prediction: check for the two common cases
+        * of a uni-directional data xfer.  If the packet has
+        * no control flags, is in-sequence, the window didn't
+        * change and we're not retransmitting, it's a
+        * candidate.  If the length is zero and the ack moved
+        * forward, we're the sender side of the xfer.  Just
+        * free the data acked & wake any higher level process
+        * that was blocked waiting for space.  If the length
+        * is non-zero and the ack didn't move, we're the
+        * receiver side.  If we're getting packets in-order
+        * (the reassembly queue is empty), add the data to
+        * the socket buffer and note that we need a delayed ack.
+        */
+       if (tp->t_state == TCPS_ESTABLISHED &&
+           (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
+           ti->ti_seq == tp->rcv_nxt &&
+           ti->ti_win && ti->ti_win == tp->snd_wnd &&
+           tp->snd_nxt == tp->snd_max) {
+               if (ti->ti_len == 0) {
+                       if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
+                           SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
+                           tp->snd_cwnd >= tp->snd_wnd) {
+                               /*
+                                * this is a pure ack for outstanding data.
+                                */
+                               ++tcppredack;
+                               if (tp->t_rtt && SEQ_GT(ti->ti_ack,tp->t_rtseq))
+                                       tcp_xmit_timer(tp);
+                               acked = ti->ti_ack - tp->snd_una;
+                               tcpstat.tcps_rcvackpack++;
+                               tcpstat.tcps_rcvackbyte += acked;
+                               sbdrop(&so->so_snd, acked);
+                               tp->snd_una = ti->ti_ack;
+                               m_freem(m);
+
+                               /*
+                                * If all outstanding data are acked, stop
+                                * retransmit timer, otherwise restart timer
+                                * using current (possibly backed-off) value.
+                                * If process is waiting for space,
+                                * wakeup/selwakeup/signal.  If data
+                                * are ready to send, let tcp_output
+                                * decide between more output or persist.
+                                */
+                               if (tp->snd_una == tp->snd_max)
+                                       tp->t_timer[TCPT_REXMT] = 0;
+                               else if (tp->t_timer[TCPT_PERSIST] == 0)
+                                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+
+                               if (so->so_snd.sb_flags & SB_NOTIFY)
+                                       sowwakeup(so);
+                               if (so->so_snd.sb_cc)
+                                       (void) tcp_output(tp);
+                               return;
+                       }
+               } else if (ti->ti_ack == tp->snd_una &&
+                   tp->seg_next == (struct tcpiphdr *)tp &&
+                   ti->ti_len <= sbspace(&so->so_rcv)) {
+                       /*
+                        * this is a pure, in-sequence data packet
+                        * with nothing on the reassembly queue and
+                        * we have enough buffer space to take it.
+                        */
+                       ++tcppreddat;
+                       tp->rcv_nxt += ti->ti_len;
+                       tcpstat.tcps_rcvpack++;
+                       tcpstat.tcps_rcvbyte += ti->ti_len;
+                       /*
+                        * Drop TCP and IP headers then add data
+                        * to socket buffer
+                        */
+                       m->m_data += sizeof(struct tcpiphdr);
+                       m->m_len -= sizeof(struct tcpiphdr);
+                       sbappend(&so->so_rcv, m);
+                       sorwakeup(so);
+                       tp->t_flags |= TF_DELACK;
+                       return;
+               }
+       }
+
+       /*
+        * Drop TCP and IP headers; TCP options were dropped above.
+        */
+       m->m_data += sizeof(struct tcpiphdr);
+       m->m_len -= sizeof(struct tcpiphdr);
+
+       /*
+        * Calculate amount of space in receive window,
+        * and then do TCP input processing.
+        * Receive window is amount of space in rcv queue,
+        * but not less than advertised window.
+        */
+       { int win;
+
+       win = sbspace(&so->so_rcv);
+       if (win < 0)
+               win = 0;
+       tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
+       }
+
+       switch (tp->t_state) {
+
+       /*
+        * If the state is LISTEN then ignore segment if it contains an RST.
+        * If the segment contains an ACK then it is bad and send a RST.
+        * If it does not contain a SYN then it is not interesting; drop it.
+        * Don't bother responding if the destination was a broadcast.
+        * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
+        * tp->iss, and send a segment:
+        *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
+        * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
+        * Fill in remote peer address fields if not previously specified.
+        * Enter SYN_RECEIVED state, and process any other fields of this
+        * segment in this state.
+        */
+       case TCPS_LISTEN: {
+               struct mbuf *am;
+               register struct sockaddr_in *sin;
+
+               if (tiflags & TH_RST)
+                       goto drop;
+               if (tiflags & TH_ACK)
+                       goto dropwithreset;
+               if ((tiflags & TH_SYN) == 0)
+                       goto drop;
+               if (m->m_flags & M_BCAST)
+                       goto drop;
+               am = m_get(M_DONTWAIT, MT_SONAME);      /* XXX */
+               if (am == NULL)
+                       goto drop;
+               am->m_len = sizeof (struct sockaddr_in);
+               sin = mtod(am, struct sockaddr_in *);
+               sin->sin_family = AF_INET;
+               sin->sin_len = sizeof(*sin);
+               sin->sin_addr = ti->ti_src;
+               sin->sin_port = ti->ti_sport;
+               laddr = inp->inp_laddr;
+               if (inp->inp_laddr.s_addr == INADDR_ANY)
+                       inp->inp_laddr = ti->ti_dst;
+               if (in_pcbconnect(inp, am)) {
+                       inp->inp_laddr = laddr;
+                       (void) m_free(am);
+                       goto drop;
+               }
+               (void) m_free(am);
+               tp->t_template = tcp_template(tp);
+               if (tp->t_template == 0) {
+                       tp = tcp_drop(tp, ENOBUFS);
+                       dropsocket = 0;         /* socket is already gone */
+                       goto drop;
+               }
+               if (om) {
+                       tcp_dooptions(tp, om, ti);
+                       om = 0;
+               }
+               if (iss)
+                       tp->iss = iss;
+               else
+                       tp->iss = tcp_iss;
+               tcp_iss += TCP_ISSINCR/2;
+               tp->irs = ti->ti_seq;
+               tcp_sendseqinit(tp);
+               tcp_rcvseqinit(tp);
+               tp->t_flags |= TF_ACKNOW;
+               tp->t_state = TCPS_SYN_RECEIVED;
+               tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+               dropsocket = 0;         /* committed to socket */
+               tcpstat.tcps_accepts++;
+               goto trimthenstep6;
+               }
+
+       /*
+        * If the state is SYN_SENT:
+        *      if seg contains an ACK, but not for our SYN, drop the input.
+        *      if seg contains a RST, then drop the connection.
+        *      if seg does not contain SYN, then drop it.
+        * Otherwise this is an acceptable SYN segment
+        *      initialize tp->rcv_nxt and tp->irs
+        *      if seg contains ack then advance tp->snd_una
+        *      if SYN has been acked change to ESTABLISHED else SYN_RCVD state
+        *      arrange for segment to be acked (eventually)
+        *      continue processing rest of data/controls, beginning with URG
+        */
+       case TCPS_SYN_SENT:
+               if ((tiflags & TH_ACK) &&
+                   (SEQ_LEQ(ti->ti_ack, tp->iss) ||
+                    SEQ_GT(ti->ti_ack, tp->snd_max)))
+                       goto dropwithreset;
+               if (tiflags & TH_RST) {
+                       if (tiflags & TH_ACK)
+                               tp = tcp_drop(tp, ECONNREFUSED);
+                       goto drop;
+               }
+               if ((tiflags & TH_SYN) == 0)
+                       goto drop;
+               if (tiflags & TH_ACK) {
+                       tp->snd_una = ti->ti_ack;
+                       if (SEQ_LT(tp->snd_nxt, tp->snd_una))
+                               tp->snd_nxt = tp->snd_una;
+               }
+               tp->t_timer[TCPT_REXMT] = 0;
+               tp->irs = ti->ti_seq;
+               tcp_rcvseqinit(tp);
+               tp->t_flags |= TF_ACKNOW;
+               if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
+                       tcpstat.tcps_connects++;
+                       soisconnected(so);
+                       tp->t_state = TCPS_ESTABLISHED;
+                       (void) tcp_reass(tp, (struct tcpiphdr *)0,
+                               (struct mbuf *)0);
+                       /*
+                        * if we didn't have to retransmit the SYN,
+                        * use its rtt as our initial srtt & rtt var.
+                        */
+                       if (tp->t_rtt)
+                               tcp_xmit_timer(tp);
+               } else
+                       tp->t_state = TCPS_SYN_RECEIVED;
+
+trimthenstep6:
+               /*
+                * Advance ti->ti_seq to correspond to first data byte.
+                * If data, trim to stay within window,
+                * dropping FIN if necessary.
+                */
+               ti->ti_seq++;
+               if (ti->ti_len > tp->rcv_wnd) {
+                       todrop = ti->ti_len - tp->rcv_wnd;
+                       m_adj(m, -todrop);
+                       ti->ti_len = tp->rcv_wnd;
+                       tiflags &= ~TH_FIN;
+                       tcpstat.tcps_rcvpackafterwin++;
+                       tcpstat.tcps_rcvbyteafterwin += todrop;
+               }
+               tp->snd_wl1 = ti->ti_seq - 1;
+               tp->rcv_up = ti->ti_seq;
+               goto step6;
+       }
+
+       /*
+        * States other than LISTEN or SYN_SENT.
+        * First check that at least some bytes of segment are within 
+        * receive window.  If segment begins before rcv_nxt,
+        * drop leading data (and SYN); if nothing left, just ack.
+        */
+       todrop = tp->rcv_nxt - ti->ti_seq;
+       if (todrop > 0) {
+               if (tiflags & TH_SYN) {
+                       tiflags &= ~TH_SYN;
+                       ti->ti_seq++;
+                       if (ti->ti_urp > 1) 
+                               ti->ti_urp--;
+                       else
+                               tiflags &= ~TH_URG;
+                       todrop--;
+               }
+               if (todrop > ti->ti_len ||
+                   todrop == ti->ti_len && (tiflags&TH_FIN) == 0) {
+                       tcpstat.tcps_rcvduppack++;
+                       tcpstat.tcps_rcvdupbyte += ti->ti_len;
+                       /*
+                        * If segment is just one to the left of the window,
+                        * check two special cases:
+                        * 1. Don't toss RST in response to 4.2-style keepalive.
+                        * 2. If the only thing to drop is a FIN, we can drop
+                        *    it, but check the ACK or we will get into FIN
+                        *    wars if our FINs crossed (both CLOSING).
+                        * In either case, send ACK to resynchronize,
+                        * but keep on processing for RST or ACK.
+                        */
+                       if ((tiflags & TH_FIN && todrop == ti->ti_len + 1)
+#ifdef TCP_COMPAT_42
+                         || (tiflags & TH_RST && ti->ti_seq == tp->rcv_nxt - 1)
+#endif
+                          ) {
+                               todrop = ti->ti_len;
+                               tiflags &= ~TH_FIN;
+                               tp->t_flags |= TF_ACKNOW;
+                       } else
+                               goto dropafterack;
+               } else {
+                       tcpstat.tcps_rcvpartduppack++;
+                       tcpstat.tcps_rcvpartdupbyte += todrop;
+               }
+               m_adj(m, todrop);
+               ti->ti_seq += todrop;
+               ti->ti_len -= todrop;
+               if (ti->ti_urp > todrop)
+                       ti->ti_urp -= todrop;
+               else {
+                       tiflags &= ~TH_URG;
+                       ti->ti_urp = 0;
+               }
+       }
+
+       /*
+        * If new data are received on a connection after the
+        * user processes are gone, then RST the other end.
+        */
+       if ((so->so_state & SS_NOFDREF) &&
+           tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
+               tp = tcp_close(tp);
+               tcpstat.tcps_rcvafterclose++;
+               goto dropwithreset;
+       }
+
+       /*
+        * If segment ends after window, drop trailing data
+        * (and PUSH and FIN); if nothing left, just ACK.
+        */
+       todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
+       if (todrop > 0) {
+               tcpstat.tcps_rcvpackafterwin++;
+               if (todrop >= ti->ti_len) {
+                       tcpstat.tcps_rcvbyteafterwin += ti->ti_len;
+                       /*
+                        * If a new connection request is received
+                        * while in TIME_WAIT, drop the old connection
+                        * and start over if the sequence numbers
+                        * are above the previous ones.
+                        */
+                       if (tiflags & TH_SYN &&
+                           tp->t_state == TCPS_TIME_WAIT &&
+                           SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
+                               iss = tp->rcv_nxt + TCP_ISSINCR;
+                               tp = tcp_close(tp);
+                               goto findpcb;
+                       }
+                       /*
+                        * If window is closed can only take segments at
+                        * window edge, and have to drop data and PUSH from
+                        * incoming segments.  Continue processing, but
+                        * remember to ack.  Otherwise, drop segment
+                        * and ack.
+                        */
+                       if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
+                               tp->t_flags |= TF_ACKNOW;
+                               tcpstat.tcps_rcvwinprobe++;
+                       } else
+                               goto dropafterack;
+               } else
+                       tcpstat.tcps_rcvbyteafterwin += todrop;
+               m_adj(m, -todrop);
+               ti->ti_len -= todrop;
+               tiflags &= ~(TH_PUSH|TH_FIN);
+       }
+
+       /*
+        * If the RST bit is set examine the state:
+        *    SYN_RECEIVED STATE:
+        *      If passive open, return to LISTEN state.
+        *      If active open, inform user that connection was refused.
+        *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
+        *      Inform user that connection was reset, and close tcb.
+        *    CLOSING, LAST_ACK, TIME_WAIT STATES
+        *      Close the tcb.
+        */
+       if (tiflags&TH_RST) switch (tp->t_state) {
+
+       case TCPS_SYN_RECEIVED:
+               so->so_error = ECONNREFUSED;
+               goto close;
+
+       case TCPS_ESTABLISHED:
+       case TCPS_FIN_WAIT_1:
+       case TCPS_FIN_WAIT_2:
+       case TCPS_CLOSE_WAIT:
+               so->so_error = ECONNRESET;
+       close:
+               tp->t_state = TCPS_CLOSED;
+               tcpstat.tcps_drops++;
+               tp = tcp_close(tp);
+               goto drop;
+
+       case TCPS_CLOSING:
+       case TCPS_LAST_ACK:
+       case TCPS_TIME_WAIT:
+               tp = tcp_close(tp);
+               goto drop;
+       }
+
+       /*
+        * If a SYN is in the window, then this is an
+        * error and we send an RST and drop the connection.
+        */
+       if (tiflags & TH_SYN) {
+               tp = tcp_drop(tp, ECONNRESET);
+               goto dropwithreset;
+       }
+
+       /*
+        * If the ACK bit is off we drop the segment and return.
+        */
+       if ((tiflags & TH_ACK) == 0)
+               goto drop;
+       
+       /*
+        * Ack processing.
+        */
+       switch (tp->t_state) {
+
+       /*
+        * In SYN_RECEIVED state if the ack ACKs our SYN then enter
+        * ESTABLISHED state and continue processing, otherwise
+        * send an RST.
+        */
+       case TCPS_SYN_RECEIVED:
+               if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
+                   SEQ_GT(ti->ti_ack, tp->snd_max))
+                       goto dropwithreset;
+               tcpstat.tcps_connects++;
+               soisconnected(so);
+               tp->t_state = TCPS_ESTABLISHED;
+               (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
+               tp->snd_wl1 = ti->ti_seq - 1;
+               /* fall into ... */
+
+       /*
+        * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
+        * ACKs.  If the ack is in the range
+        *      tp->snd_una < ti->ti_ack <= tp->snd_max
+        * then advance tp->snd_una to ti->ti_ack and drop
+        * data from the retransmission queue.  If this ACK reflects
+        * more up to date window information we update our window information.
+        */
+       case TCPS_ESTABLISHED:
+       case TCPS_FIN_WAIT_1:
+       case TCPS_FIN_WAIT_2:
+       case TCPS_CLOSE_WAIT:
+       case TCPS_CLOSING:
+       case TCPS_LAST_ACK:
+       case TCPS_TIME_WAIT:
+
+               if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
+                       if (ti->ti_len == 0 && ti->ti_win == tp->snd_wnd) {
+                               tcpstat.tcps_rcvdupack++;
+                               /*
+                                * If we have outstanding data (other than
+                                * a window probe), this is a completely
+                                * duplicate ack (ie, window info didn't
+                                * change), the ack is the biggest we've
+                                * seen and we've seen exactly our rexmt
+                                * threshhold of them, assume a packet
+                                * has been dropped and retransmit it.
+                                * Kludge snd_nxt & the congestion
+                                * window so we send only this one
+                                * packet.
+                                *
+                                * We know we're losing at the current
+                                * window size so do congestion avoidance
+                                * (set ssthresh to half the current window
+                                * and pull our congestion window back to
+                                * the new ssthresh).
+                                *
+                                * Dup acks mean that packets have left the
+                                * network (they're now cached at the receiver) 
+                                * so bump cwnd by the amount in the receiver
+                                * to keep a constant cwnd packets in the
+                                * network.
+                                */
+                               if (tp->t_timer[TCPT_REXMT] == 0 ||
+                                   ti->ti_ack != tp->snd_una)
+                                       tp->t_dupacks = 0;
+                               else if (++tp->t_dupacks == tcprexmtthresh) {
+                                       tcp_seq onxt = tp->snd_nxt;
+                                       u_int win =
+                                           min(tp->snd_wnd, tp->snd_cwnd) / 2 /
+                                               tp->t_maxseg;
+
+                                       if (win < 2)
+                                               win = 2;
+                                       tp->snd_ssthresh = win * tp->t_maxseg;
+                                       tp->t_timer[TCPT_REXMT] = 0;
+                                       tp->t_rtt = 0;
+                                       tp->snd_nxt = ti->ti_ack;
+                                       tp->snd_cwnd = tp->t_maxseg;
+                                       (void) tcp_output(tp);
+                                       tp->snd_cwnd = tp->snd_ssthresh +
+                                              tp->t_maxseg * tp->t_dupacks;
+                                       if (SEQ_GT(onxt, tp->snd_nxt))
+                                               tp->snd_nxt = onxt;
+                                       goto drop;
+                               } else if (tp->t_dupacks > tcprexmtthresh) {
+                                       tp->snd_cwnd += tp->t_maxseg;
+                                       (void) tcp_output(tp);
+                                       goto drop;
+                               }
+                       } else
+                               tp->t_dupacks = 0;
+                       break;
+               }
+               /*
+                * If the congestion window was inflated to account
+                * for the other side's cached packets, retract it.
+                */
+               if (tp->t_dupacks > tcprexmtthresh &&
+                   tp->snd_cwnd > tp->snd_ssthresh)
+                       tp->snd_cwnd = tp->snd_ssthresh;
+               tp->t_dupacks = 0;
+               if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
+                       tcpstat.tcps_rcvacktoomuch++;
+                       goto dropafterack;
+               }
+               acked = ti->ti_ack - tp->snd_una;
+               tcpstat.tcps_rcvackpack++;
+               tcpstat.tcps_rcvackbyte += acked;
+
+               /*
+                * If transmit timer is running and timed sequence
+                * number was acked, update smoothed round trip time.
+                * Since we now have an rtt measurement, cancel the
+                * timer backoff (cf., Phil Karn's retransmit alg.).
+                * Recompute the initial retransmit timer.
+                */
+               if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
+                       tcp_xmit_timer(tp);
+
+               /*
+                * If all outstanding data is acked, stop retransmit
+                * timer and remember to restart (more output or persist).
+                * If there is more data to be acked, restart retransmit
+                * timer, using current (possibly backed-off) value.
+                */
+               if (ti->ti_ack == tp->snd_max) {
+                       tp->t_timer[TCPT_REXMT] = 0;
+                       needoutput = 1;
+               } else if (tp->t_timer[TCPT_PERSIST] == 0)
+                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+               /*
+                * When new data is acked, open the congestion window.
+                * If the window gives us less than ssthresh packets
+                * in flight, open exponentially (maxseg per packet).
+                * Otherwise open linearly: maxseg per window
+                * (maxseg^2 / cwnd per packet), plus a constant
+                * fraction of a packet (maxseg/8) to help larger windows
+                * open quickly enough.
+                */
+               {
+               register u_int cw = tp->snd_cwnd;
+               register u_int incr = tp->t_maxseg;
+
+               if (cw > tp->snd_ssthresh)
+                       incr = incr * incr / cw + incr / 8;
+               tp->snd_cwnd = min(cw + incr, TCP_MAXWIN);
+               }
+               if (acked > so->so_snd.sb_cc) {
+                       tp->snd_wnd -= so->so_snd.sb_cc;
+                       sbdrop(&so->so_snd, (int)so->so_snd.sb_cc);
+                       ourfinisacked = 1;
+               } else {
+                       sbdrop(&so->so_snd, acked);
+                       tp->snd_wnd -= acked;
+                       ourfinisacked = 0;
+               }
+               if (so->so_snd.sb_flags & SB_NOTIFY)
+                       sowwakeup(so);
+               tp->snd_una = ti->ti_ack;
+               if (SEQ_LT(tp->snd_nxt, tp->snd_una))
+                       tp->snd_nxt = tp->snd_una;
+
+               switch (tp->t_state) {
+
+               /*
+                * In FIN_WAIT_1 STATE in addition to the processing
+                * for the ESTABLISHED state if our FIN is now acknowledged
+                * then enter FIN_WAIT_2.
+                */
+               case TCPS_FIN_WAIT_1:
+                       if (ourfinisacked) {
+                               /*
+                                * If we can't receive any more
+                                * data, then closing user can proceed.
+                                * Starting the timer is contrary to the
+                                * specification, but if we don't get a FIN
+                                * we'll hang forever.
+                                */
+                               if (so->so_state & SS_CANTRCVMORE) {
+                                       soisdisconnected(so);
+                                       tp->t_timer[TCPT_2MSL] = tcp_maxidle;
+                               }
+                               tp->t_state = TCPS_FIN_WAIT_2;
+                       }
+                       break;
+
+               /*
+                * In CLOSING STATE in addition to the processing for
+                * the ESTABLISHED state if the ACK acknowledges our FIN
+                * then enter the TIME-WAIT state, otherwise ignore
+                * the segment.
+                */
+               case TCPS_CLOSING:
+                       if (ourfinisacked) {
+                               tp->t_state = TCPS_TIME_WAIT;
+                               tcp_canceltimers(tp);
+                               tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                               soisdisconnected(so);
+                       }
+                       break;
+
+               /*
+                * In LAST_ACK, we may still be waiting for data to drain
+                * and/or to be acked, as well as for the ack of our FIN.
+                * If our FIN is now acknowledged, delete the TCB,
+                * enter the closed state and return.
+                */
+               case TCPS_LAST_ACK:
+                       if (ourfinisacked) {
+                               tp = tcp_close(tp);
+                               goto drop;
+                       }
+                       break;
+
+               /*
+                * In TIME_WAIT state the only thing that should arrive
+                * is a retransmission of the remote FIN.  Acknowledge
+                * it and restart the finack timer.
+                */
+               case TCPS_TIME_WAIT:
+                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                       goto dropafterack;
+               }
+       }
+
+step6:
+       /*
+        * Update window information.
+        * Don't look at window if no ACK: TAC's send garbage on first SYN.
+        */
+       if ((tiflags & TH_ACK) &&
+           (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq &&
+           (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
+            tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd))) {
+               /* keep track of pure window updates */
+               if (ti->ti_len == 0 &&
+                   tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)
+                       tcpstat.tcps_rcvwinupd++;
+               tp->snd_wnd = ti->ti_win;
+               tp->snd_wl1 = ti->ti_seq;
+               tp->snd_wl2 = ti->ti_ack;
+               if (tp->snd_wnd > tp->max_sndwnd)
+                       tp->max_sndwnd = tp->snd_wnd;
+               needoutput = 1;
+       }
+
+       /*
+        * Process segments with URG.
+        */
+       if ((tiflags & TH_URG) && ti->ti_urp &&
+           TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+               /*
+                * This is a kludge, but if we receive and accept
+                * random urgent pointers, we'll crash in
+                * soreceive.  It's hard to imagine someone
+                * actually wanting to send this much urgent data.
+                */
+               if (ti->ti_urp + so->so_rcv.sb_cc > SB_MAX) {
+                       ti->ti_urp = 0;                 /* XXX */
+                       tiflags &= ~TH_URG;             /* XXX */
+                       goto dodata;                    /* XXX */
+               }
+               /*
+                * If this segment advances the known urgent pointer,
+                * then mark the data stream.  This should not happen
+                * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
+                * a FIN has been received from the remote side. 
+                * In these states we ignore the URG.
+                *
+                * According to RFC961 (Assigned Protocols),
+                * the urgent pointer points to the last octet
+                * of urgent data.  We continue, however,
+                * to consider it to indicate the first octet
+                * of data past the urgent section as the original 
+                * spec states (in one of two places).
+                */
+               if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
+                       tp->rcv_up = ti->ti_seq + ti->ti_urp;
+                       so->so_oobmark = so->so_rcv.sb_cc +
+                           (tp->rcv_up - tp->rcv_nxt) - 1;
+                       if (so->so_oobmark == 0)
+                               so->so_state |= SS_RCVATMARK;
+                       sohasoutofband(so);
+                       tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA);
+               }
+               /*
+                * Remove out of band data so doesn't get presented to user.
+                * This can happen independent of advancing the URG pointer,
+                * but if two URG's are pending at once, some out-of-band
+                * data may creep in... ick.
+                */
+               if (ti->ti_urp <= ti->ti_len
+#ifdef SO_OOBINLINE
+                    && (so->so_options & SO_OOBINLINE) == 0
+#endif
+                    )
+                       tcp_pulloutofband(so, ti, m);
+       } else
+               /*
+                * If no out of band data is expected,
+                * pull receive urgent pointer along
+                * with the receive window.
+                */
+               if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
+                       tp->rcv_up = tp->rcv_nxt;
+dodata:                                                        /* XXX */
+
+       /*
+        * Process the segment text, merging it into the TCP sequencing queue,
+        * and arranging for acknowledgment of receipt if necessary.
+        * This process logically involves adjusting tp->rcv_wnd as data
+        * is presented to the user (this happens in tcp_usrreq.c,
+        * case PRU_RCVD).  If a FIN has already been received on this
+        * connection then we just ignore the text.
+        */
+       if ((ti->ti_len || (tiflags&TH_FIN)) &&
+           TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+               TCP_REASS(tp, ti, m, so, tiflags);
+               /*
+                * Note the amount of data that peer has sent into
+                * our window, in order to estimate the sender's
+                * buffer size.
+                */
+               len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt);
+       } else {
+               m_freem(m);
+               tiflags &= ~TH_FIN;
+       }
+
+       /*
+        * If FIN is received ACK the FIN and let the user know
+        * that the connection is closing.
+        */
+       if (tiflags & TH_FIN) {
+               if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
+                       socantrcvmore(so);
+                       tp->t_flags |= TF_ACKNOW;
+                       tp->rcv_nxt++;
+               }
+               switch (tp->t_state) {
+
+               /*
+                * In SYN_RECEIVED and ESTABLISHED STATES
+                * enter the CLOSE_WAIT state.
+                */
+               case TCPS_SYN_RECEIVED:
+               case TCPS_ESTABLISHED:
+                       tp->t_state = TCPS_CLOSE_WAIT;
+                       break;
+
+               /*
+                * If still in FIN_WAIT_1 STATE FIN has not been acked so
+                * enter the CLOSING state.
+                */
+               case TCPS_FIN_WAIT_1:
+                       tp->t_state = TCPS_CLOSING;
+                       break;
+
+               /*
+                * In FIN_WAIT_2 state enter the TIME_WAIT state,
+                * starting the time-wait timer, turning off the other 
+                * standard timers.
+                */
+               case TCPS_FIN_WAIT_2:
+                       tp->t_state = TCPS_TIME_WAIT;
+                       tcp_canceltimers(tp);
+                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                       soisdisconnected(so);
+                       break;
+
+               /*
+                * In TIME_WAIT state restart the 2 MSL time_wait timer.
+                */
+               case TCPS_TIME_WAIT:
+                       tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
+                       break;
+               }
+       }
+       if (so->so_options & SO_DEBUG)
+               tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0);
+
+       /*
+        * Return any desired output.
+        */
+       if (needoutput || (tp->t_flags & TF_ACKNOW))
+               (void) tcp_output(tp);
+       return;
+
+dropafterack:
+       /*
+        * Generate an ACK dropping incoming segment if it occupies
+        * sequence space, where the ACK reflects our state.
+        */
+       if (tiflags & TH_RST)
+               goto drop;
+       m_freem(m);
+       tp->t_flags |= TF_ACKNOW;
+       (void) tcp_output(tp);
+       return;
+
+dropwithreset:
+       if (om) {
+               (void) m_free(om);
+               om = 0;
+       }
+       /*
+        * Generate a RST, dropping incoming segment.
+        * Make ACK acceptable to originator of segment.
+        * Don't bother to respond if destination was broadcast.
+        */
+       if ((tiflags & TH_RST) || m->m_flags & M_BCAST)
+               goto drop;
+       if (tiflags & TH_ACK)
+               tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
+       else {
+               if (tiflags & TH_SYN)
+                       ti->ti_len++;
+               tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,
+                   TH_RST|TH_ACK);
+       }
+       /* destroy temporarily created socket */
+       if (dropsocket)
+               (void) soabort(so);
+       return;
+
+drop:
+       if (om)
+               (void) m_free(om);
+       /*
+        * Drop space held by incoming segment and return.
+        */
+       if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+               tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0);
+       m_freem(m);
+       /* destroy temporarily created socket */
+       if (dropsocket)
+               (void) soabort(so);
+       return;
+}
+
+tcp_dooptions(tp, om, ti)
+       struct tcpcb *tp;
+       struct mbuf *om;
+       struct tcpiphdr *ti;
+{
+       register u_char *cp;
+       u_short mss;
+       int opt, optlen, cnt;
+
+       cp = mtod(om, u_char *);
+       cnt = om->m_len;
+       for (; cnt > 0; cnt -= optlen, cp += optlen) {
+               opt = cp[0];
+               if (opt == TCPOPT_EOL)
+                       break;
+               if (opt == TCPOPT_NOP)
+                       optlen = 1;
+               else {
+                       optlen = cp[1];
+                       if (optlen <= 0)
+                               break;
+               }
+               switch (opt) {
+
+               default:
+                       continue;
+
+               case TCPOPT_MAXSEG:
+                       if (optlen != 4)
+                               continue;
+                       if (!(ti->ti_flags & TH_SYN))
+                               continue;
+                       bcopy((char *) cp + 2, (char *) &mss, sizeof(mss));
+                       NTOHS(mss);
+                       (void) tcp_mss(tp, mss);        /* sets t_maxseg */
+                       break;
+               }
+       }
+       (void) m_free(om);
+}
+
+/*
+ * Pull out of band byte out of a segment so
+ * it doesn't appear in the user's data queue.
+ * It is still reflected in the segment length for
+ * sequencing purposes.
+ */
+tcp_pulloutofband(so, ti, m)
+       struct socket *so;
+       struct tcpiphdr *ti;
+       register struct mbuf *m;
+{
+       int cnt = ti->ti_urp - 1;
+       
+       while (cnt >= 0) {
+               if (m->m_len > cnt) {
+                       char *cp = mtod(m, caddr_t) + cnt;
+                       struct tcpcb *tp = sototcpcb(so);
+
+                       tp->t_iobc = *cp;
+                       tp->t_oobflags |= TCPOOB_HAVEDATA;
+                       bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1));
+                       m->m_len--;
+                       return;
+               }
+               cnt -= m->m_len;
+               m = m->m_next;
+               if (m == 0)
+                       break;
+       }
+       panic("tcp_pulloutofband");
+}
+
+/*
+ * Collect new round-trip time estimate
+ * and update averages and current timeout.
+ */
+tcp_xmit_timer(tp)
+       register struct tcpcb *tp;
+{
+       register short delta;
+
+       tcpstat.tcps_rttupdated++;
+       if (tp->t_srtt != 0) {
+               /*
+                * srtt is stored as fixed point with 3 bits after the
+                * binary point (i.e., scaled by 8).  The following magic
+                * is equivalent to the smoothing algorithm in rfc793 with
+                * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
+                * point).  Adjust t_rtt to origin 0.
+                */
+               delta = tp->t_rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT);
+               if ((tp->t_srtt += delta) <= 0)
+                       tp->t_srtt = 1;
+               /*
+                * We accumulate a smoothed rtt variance (actually, a
+                * smoothed mean difference), then set the retransmit
+                * timer to smoothed rtt + 4 times the smoothed variance.
+                * rttvar is stored as fixed point with 2 bits after the
+                * binary point (scaled by 4).  The following is
+                * equivalent to rfc793 smoothing with an alpha of .75
+                * (rttvar = rttvar*3/4 + |delta| / 4).  This replaces
+                * rfc793's wired-in beta.
+                */
+               if (delta < 0)
+                       delta = -delta;
+               delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT);
+               if ((tp->t_rttvar += delta) <= 0)
+                       tp->t_rttvar = 1;
+       } else {
+               /* 
+                * No rtt measurement yet - use the unsmoothed rtt.
+                * Set the variance to half the rtt (so our first
+                * retransmit happens at 2*rtt)
+                */
+               tp->t_srtt = tp->t_rtt << TCP_RTT_SHIFT;
+               tp->t_rttvar = tp->t_rtt << (TCP_RTTVAR_SHIFT - 1);
+       }
+       tp->t_rtt = 0;
+       tp->t_rxtshift = 0;
+
+       /*
+        * the retransmit should happen at rtt + 4 * rttvar.
+        * Because of the way we do the smoothing, srtt and rttvar
+        * will each average +1/2 tick of bias.  When we compute
+        * the retransmit timer, we want 1/2 tick of rounding and
+        * 1 extra tick because of +-1/2 tick uncertainty in the
+        * firing of the timer.  The bias will give us exactly the
+        * 1.5 tick we need.  But, because the bias is
+        * statistical, we have to test that we don't drop below
+        * the minimum feasible timer (which is 2 ticks).
+        */
+       TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
+           tp->t_rttmin, TCPTV_REXMTMAX);
+       
+       /*
+        * We received an ack for a packet that wasn't retransmitted;
+        * it is probably safe to discard any error indications we've
+        * received recently.  This isn't quite right, but close enough
+        * for now (a route might have failed after we sent a segment,
+        * and the return path might not be symmetrical).
+        */
+       tp->t_softerror = 0;
+}
+
+/*
+ * Determine a reasonable value for maxseg size.
+ * If the route is known, check route for mtu.
+ * If none, use an mss that can be handled on the outgoing
+ * interface without forcing IP to fragment; if bigger than
+ * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES
+ * to utilize large mbufs.  If no route is found, route has no mtu,
+ * or the destination isn't local, use a default, hopefully conservative
+ * size (usually 512 or the default IP max size, but no more than the mtu
+ * of the interface), as we can't discover anything about intervening
+ * gateways or networks.  We also initialize the congestion/slow start
+ * window to be a single segment if the destination isn't local.
+ * While looking at the routing entry, we also initialize other path-dependent
+ * parameters from pre-set or cached values in the routing entry.
+ */
+
+tcp_mss(tp, offer)
+       register struct tcpcb *tp;
+       u_short offer;
+{
+       struct route *ro;
+       register struct rtentry *rt;
+       struct ifnet *ifp;
+       register int rtt, mss;
+       u_long bufsize;
+       struct inpcb *inp;
+       struct socket *so;
+       extern int tcp_mssdflt, tcp_rttdflt;
+
+       inp = tp->t_inpcb;
+       ro = &inp->inp_route;
+
+       if ((rt = ro->ro_rt) == (struct rtentry *)0) {
+               /* No route yet, so try to acquire one */
+               if (inp->inp_faddr.s_addr != INADDR_ANY) {
+                       ro->ro_dst.sa_family = AF_INET;
+                       ro->ro_dst.sa_len = sizeof(ro->ro_dst);
+                       ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
+                               inp->inp_faddr;
+                       rtalloc(ro);
+               }
+               if ((rt = ro->ro_rt) == (struct rtentry *)0)
+                       return (tcp_mssdflt);
+       }
+       ifp = rt->rt_ifp;
+       so = inp->inp_socket;
+
+#ifdef RTV_MTU /* if route characteristics exist ... */
+       /*
+        * While we're here, check if there's an initial rtt
+        * or rttvar.  Convert from the route-table units
+        * to scaled multiples of the slow timeout timer.
+        */
+       if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
+               if (rt->rt_rmx.rmx_locks & RTV_MTU)
+                       tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ);
+               tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
+               if (rt->rt_rmx.rmx_rttvar)
+                       tp->t_rttvar = rt->rt_rmx.rmx_rttvar /
+                           (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
+               else
+                       /* default variation is +- 1 rtt */
+                       tp->t_rttvar =
+                           tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE;
+               TCPT_RANGESET(tp->t_rxtcur,
+                   ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,
+                   tp->t_rttmin, TCPTV_REXMTMAX);
+       }
+       /*
+        * if there's an mtu associated with the route, use it
+        */
+       if (rt->rt_rmx.rmx_mtu)
+               mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
+       else
+#endif /* RTV_MTU */
+       {
+               mss = ifp->if_mtu - sizeof(struct tcpiphdr);
+#if    (MCLBYTES & (MCLBYTES - 1)) == 0
+               if (mss > MCLBYTES)
+                       mss &= ~(MCLBYTES-1);
+#else
+               if (mss > MCLBYTES)
+                       mss = mss / MCLBYTES * MCLBYTES;
+#endif
+               if (!in_localaddr(inp->inp_faddr))
+                       mss = min(mss, tcp_mssdflt);
+       }
+       /*
+        * The current mss, t_maxseg, is initialized to the default value.
+        * If we compute a smaller value, reduce the current mss.
+        * If we compute a larger value, return it for use in sending
+        * a max seg size option, but don't store it for use
+        * unless we received an offer at least that large from peer.
+        * However, do not accept offers under 32 bytes.
+        */
+       if (offer)
+               mss = min(mss, offer);
+       mss = max(mss, 32);             /* sanity */
+       if (mss < tp->t_maxseg || offer != 0) {
+               /*
+                * If there's a pipesize, change the socket buffer
+                * to that size.  Make the socket buffers an integral
+                * number of mss units; if the mss is larger than
+                * the socket buffer, decrease the mss.
+                */
+#ifdef RTV_SPIPE
+               if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0)
+#endif
+                       bufsize = so->so_snd.sb_hiwat;
+               if (bufsize < mss)
+                       mss = bufsize;
+               else {
+                       bufsize = min(bufsize, SB_MAX) / mss * mss;
+                       (void) sbreserve(&so->so_snd, bufsize);
+               }
+               tp->t_maxseg = mss;
+
+#ifdef RTV_RPIPE
+               if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0)
+#endif
+                       bufsize = so->so_rcv.sb_hiwat;
+               if (bufsize > mss) {
+                       bufsize = min(bufsize, SB_MAX) / mss * mss;
+                       (void) sbreserve(&so->so_rcv, bufsize);
+               }
+       }
+       tp->snd_cwnd = mss;
+
+#ifdef RTV_SSTHRESH
+       if (rt->rt_rmx.rmx_ssthresh) {
+               /*
+                * There's some sort of gateway or interface
+                * buffer limit on the path.  Use this to set
+                * the slow start threshhold, but set the
+                * threshold to no less than 2*mss.
+                */
+               tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh);
+       }
+#endif /* RTV_MTU */
+       return (mss);
+}
diff --git a/usr/src/sys.386bsd/netinet/tcp_output.c b/usr/src/sys.386bsd/netinet/tcp_output.c
new file mode 100644 (file)
index 0000000..167b193
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_output.c        7.22 (Berkeley) 8/31/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "errno.h"
+
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "ip_var.h"
+#include "tcp.h"
+#define        TCPOUTFLAGS
+#include "tcp_fsm.h"
+#include "tcp_seq.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+#include "tcp_debug.h"
+
+#ifdef notyet
+extern struct mbuf *m_copypack();
+#endif
+
+/*
+ * Initial options.
+ */
+u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, };
+
+/*
+ * Tcp output routine: figure out what should be sent and send it.
+ */
+tcp_output(tp)
+       register struct tcpcb *tp;
+{
+       register struct socket *so = tp->t_inpcb->inp_socket;
+       register long len, win;
+       int off, flags, error;
+       register struct mbuf *m;
+       register struct tcpiphdr *ti;
+       u_char *opt;
+       unsigned optlen, hdrlen;
+       int idle, sendalot;
+
+       /*
+        * Determine length of data that should be transmitted,
+        * and flags that will be used.
+        * If there is some data or critical controls (SYN, RST)
+        * to send, then transmit; otherwise, investigate further.
+        */
+       idle = (tp->snd_max == tp->snd_una);
+       if (idle && tp->t_idle >= tp->t_rxtcur)
+               /*
+                * We have been idle for "a while" and no acks are
+                * expected to clock out any data we send --
+                * slow start to get ack "clock" running again.
+                */
+               tp->snd_cwnd = tp->t_maxseg;
+again:
+       sendalot = 0;
+       off = tp->snd_nxt - tp->snd_una;
+       win = min(tp->snd_wnd, tp->snd_cwnd);
+
+       /*
+        * If in persist timeout with window of 0, send 1 byte.
+        * Otherwise, if window is small but nonzero
+        * and timer expired, we will send what we can
+        * and go to transmit state.
+        */
+       if (tp->t_force) {
+               if (win == 0)
+                       win = 1;
+               else {
+                       tp->t_timer[TCPT_PERSIST] = 0;
+                       tp->t_rxtshift = 0;
+               }
+       }
+
+       flags = tcp_outflags[tp->t_state];
+       len = min(so->so_snd.sb_cc, win) - off;
+
+       if (len < 0) {
+               /*
+                * If FIN has been sent but not acked,
+                * but we haven't been called to retransmit,
+                * len will be -1.  Otherwise, window shrank
+                * after we sent into it.  If window shrank to 0,
+                * cancel pending retransmit and pull snd_nxt
+                * back to (closed) window.  We will enter persist
+                * state below.  If the window didn't close completely,
+                * just wait for an ACK.
+                */
+               len = 0;
+               if (win == 0) {
+                       tp->t_timer[TCPT_REXMT] = 0;
+                       tp->snd_nxt = tp->snd_una;
+               }
+       }
+       if (len > tp->t_maxseg) {
+               len = tp->t_maxseg;
+               sendalot = 1;
+       }
+       if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
+               flags &= ~TH_FIN;
+
+       win = sbspace(&so->so_rcv);
+
+       /*
+        * Sender silly window avoidance.  If connection is idle
+        * and can send all data, a maximum segment,
+        * at least a maximum default-size segment do it,
+        * or are forced, do it; otherwise don't bother.
+        * If peer's buffer is tiny, then send
+        * when window is at least half open.
+        * If retransmitting (possibly after persist timer forced us
+        * to send into a small window), then must resend.
+        */
+       if (len) {
+               if (len == tp->t_maxseg)
+                       goto send;
+               if ((idle || tp->t_flags & TF_NODELAY) &&
+                   len + off >= so->so_snd.sb_cc)
+                       goto send;
+               if (tp->t_force)
+                       goto send;
+               if (len >= tp->max_sndwnd / 2)
+                       goto send;
+               if (SEQ_LT(tp->snd_nxt, tp->snd_max))
+                       goto send;
+       }
+
+       /*
+        * Compare available window to amount of window
+        * known to peer (as advertised window less
+        * next expected input).  If the difference is at least two
+        * max size segments, or at least 50% of the maximum possible
+        * window, then want to send a window update to peer.
+        */
+       if (win > 0) {
+               long adv = win - (tp->rcv_adv - tp->rcv_nxt);
+
+               if (adv >= (long) (2 * tp->t_maxseg))
+                       goto send;
+               if (2 * adv >= (long) so->so_rcv.sb_hiwat)
+                       goto send;
+       }
+
+       /*
+        * Send if we owe peer an ACK.
+        */
+       if (tp->t_flags & TF_ACKNOW)
+               goto send;
+       if (flags & (TH_SYN|TH_RST))
+               goto send;
+       if (SEQ_GT(tp->snd_up, tp->snd_una))
+               goto send;
+       /*
+        * If our state indicates that FIN should be sent
+        * and we have not yet done so, or we're retransmitting the FIN,
+        * then we need to send.
+        */
+       if (flags & TH_FIN &&
+           ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
+               goto send;
+
+       /*
+        * TCP window updates are not reliable, rather a polling protocol
+        * using ``persist'' packets is used to insure receipt of window
+        * updates.  The three ``states'' for the output side are:
+        *      idle                    not doing retransmits or persists
+        *      persisting              to move a small or zero window
+        *      (re)transmitting        and thereby not persisting
+        *
+        * tp->t_timer[TCPT_PERSIST]
+        *      is set when we are in persist state.
+        * tp->t_force
+        *      is set when we are called to send a persist packet.
+        * tp->t_timer[TCPT_REXMT]
+        *      is set when we are retransmitting
+        * The output side is idle when both timers are zero.
+        *
+        * If send window is too small, there is data to transmit, and no
+        * retransmit or persist is pending, then go to persist state.
+        * If nothing happens soon, send when timer expires:
+        * if window is nonzero, transmit what we can,
+        * otherwise force out a byte.
+        */
+       if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
+           tp->t_timer[TCPT_PERSIST] == 0) {
+               tp->t_rxtshift = 0;
+               tcp_setpersist(tp);
+       }
+
+       /*
+        * No reason to send a segment, just return.
+        */
+       return (0);
+
+send:
+       /*
+        * Before ESTABLISHED, force sending of initial options
+        * unless TCP set not to do any options.
+        * NOTE: we assume that the IP/TCP header plus TCP options
+        * always fit in a single mbuf, leaving room for a maximum
+        * link header, i.e.
+        *      max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
+        */
+       optlen = 0;
+       hdrlen = sizeof (struct tcpiphdr);
+       if (flags & TH_SYN && (tp->t_flags & TF_NOOPT) == 0) {
+               opt = tcp_initopt;
+               optlen = sizeof (tcp_initopt);
+               hdrlen += sizeof (tcp_initopt);
+               *(u_short *)(opt + 2) = htons((u_short) tcp_mss(tp, 0));
+#ifdef DIAGNOSTIC
+               if (max_linkhdr + hdrlen > MHLEN)
+                       panic("tcphdr too big");
+#endif
+       }
+
+       /*
+        * Grab a header mbuf, attaching a copy of data to
+        * be transmitted, and initialize the header from
+        * the template for sends on this connection.
+        */
+       if (len) {
+               if (tp->t_force && len == 1)
+                       tcpstat.tcps_sndprobe++;
+               else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
+                       tcpstat.tcps_sndrexmitpack++;
+                       tcpstat.tcps_sndrexmitbyte += len;
+               } else {
+                       tcpstat.tcps_sndpack++;
+                       tcpstat.tcps_sndbyte += len;
+               }
+#ifdef notyet
+               if ((m = m_copypack(so->so_snd.sb_mb, off,
+                   (int)len, max_linkhdr + hdrlen)) == 0) {
+                       error = ENOBUFS;
+                       goto out;
+               }
+               /*
+                * m_copypack left space for our hdr; use it.
+                */
+               m->m_len += hdrlen;
+               m->m_data -= hdrlen;
+#else
+               MGETHDR(m, M_DONTWAIT, MT_HEADER);
+               if (m == NULL) {
+                       error = ENOBUFS;
+                       goto out;
+               }
+               m->m_data += max_linkhdr;
+               m->m_len = hdrlen;
+               if (len <= MHLEN - hdrlen - max_linkhdr) {
+                       m_copydata(so->so_snd.sb_mb, off, (int) len,
+                           mtod(m, caddr_t) + hdrlen);
+                       m->m_len += len;
+               } else {
+                       m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
+                       if (m->m_next == 0)
+                               len = 0;
+               }
+#endif
+               /*
+                * If we're sending everything we've got, set PUSH.
+                * (This will keep happy those implementations which only
+                * give data to the user when a buffer fills or
+                * a PUSH comes in.)
+                */
+               if (off + len == so->so_snd.sb_cc)
+                       flags |= TH_PUSH;
+       } else {
+               if (tp->t_flags & TF_ACKNOW)
+                       tcpstat.tcps_sndacks++;
+               else if (flags & (TH_SYN|TH_FIN|TH_RST))
+                       tcpstat.tcps_sndctrl++;
+               else if (SEQ_GT(tp->snd_up, tp->snd_una))
+                       tcpstat.tcps_sndurg++;
+               else
+                       tcpstat.tcps_sndwinup++;
+
+               MGETHDR(m, M_DONTWAIT, MT_HEADER);
+               if (m == NULL) {
+                       error = ENOBUFS;
+                       goto out;
+               }
+               m->m_data += max_linkhdr;
+               m->m_len = hdrlen;
+       }
+       m->m_pkthdr.rcvif = (struct ifnet *)0;
+       ti = mtod(m, struct tcpiphdr *);
+       if (tp->t_template == 0)
+               panic("tcp_output");
+       bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr));
+
+       /*
+        * Fill in fields, remembering maximum advertised
+        * window for use in delaying messages about window sizes.
+        * If resending a FIN, be sure not to use a new sequence number.
+        */
+       if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && 
+           tp->snd_nxt == tp->snd_max)
+               tp->snd_nxt--;
+       ti->ti_seq = htonl(tp->snd_nxt);
+       ti->ti_ack = htonl(tp->rcv_nxt);
+       if (optlen) {
+               bcopy((caddr_t)opt, (caddr_t)(ti + 1), optlen);
+               ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
+       }
+       ti->ti_flags = flags;
+       /*
+        * Calculate receive window.  Don't shrink window,
+        * but avoid silly window syndrome.
+        */
+       if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg)
+               win = 0;
+       if (win > TCP_MAXWIN)
+               win = TCP_MAXWIN;
+       if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
+               win = (long)(tp->rcv_adv - tp->rcv_nxt);
+       ti->ti_win = htons((u_short)win);
+       if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
+               ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));
+               ti->ti_flags |= TH_URG;
+       } else
+               /*
+                * If no urgent pointer to send, then we pull
+                * the urgent pointer to the left edge of the send window
+                * so that it doesn't drift into the send window on sequence
+                * number wraparound.
+                */
+               tp->snd_up = tp->snd_una;               /* drag it along */
+
+       /*
+        * Put TCP length in extended header, and then
+        * checksum extended header and data.
+        */
+       if (len + optlen)
+               ti->ti_len = htons((u_short)(sizeof (struct tcphdr) +
+                   optlen + len));
+       ti->ti_sum = in_cksum(m, (int)(hdrlen + len));
+
+       /*
+        * In transmit state, time the transmission and arrange for
+        * the retransmit.  In persist state, just set snd_max.
+        */
+       if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {
+               tcp_seq startseq = tp->snd_nxt;
+
+               /*
+                * Advance snd_nxt over sequence space of this segment.
+                */
+               if (flags & (TH_SYN|TH_FIN)) {
+                       if (flags & TH_SYN)
+                               tp->snd_nxt++;
+                       if (flags & TH_FIN) {
+                               tp->snd_nxt++;
+                               tp->t_flags |= TF_SENTFIN;
+                       }
+               }
+               tp->snd_nxt += len;
+               if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
+                       tp->snd_max = tp->snd_nxt;
+                       /*
+                        * Time this transmission if not a retransmission and
+                        * not currently timing anything.
+                        */
+                       if (tp->t_rtt == 0) {
+                               tp->t_rtt = 1;
+                               tp->t_rtseq = startseq;
+                               tcpstat.tcps_segstimed++;
+                       }
+               }
+
+               /*
+                * Set retransmit timer if not currently set,
+                * and not doing an ack or a keep-alive probe.
+                * Initial value for retransmit timer is smoothed
+                * round-trip time + 2 * round-trip time variance.
+                * Initialize shift counter which is used for backoff
+                * of retransmit time.
+                */
+               if (tp->t_timer[TCPT_REXMT] == 0 &&
+                   tp->snd_nxt != tp->snd_una) {
+                       tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+                       if (tp->t_timer[TCPT_PERSIST]) {
+                               tp->t_timer[TCPT_PERSIST] = 0;
+                               tp->t_rxtshift = 0;
+                       }
+               }
+       } else
+               if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
+                       tp->snd_max = tp->snd_nxt + len;
+
+       /*
+        * Trace.
+        */
+       if (so->so_options & SO_DEBUG)
+               tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0);
+
+       /*
+        * Fill in IP length and desired time to live and
+        * send to IP level.  There should be a better way
+        * to handle ttl and tos; we could keep them in
+        * the template, but need a way to checksum without them.
+        */
+       m->m_pkthdr.len = hdrlen + len;
+       ((struct ip *)ti)->ip_len = m->m_pkthdr.len;
+       ((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip.ip_ttl; /* XXX */
+       ((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip.ip_tos; /* XXX */
+#if BSD >= 43
+       error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
+           so->so_options & SO_DONTROUTE);
+#else
+       error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, 
+           so->so_options & SO_DONTROUTE);
+#endif
+       if (error) {
+out:
+               if (error == ENOBUFS) {
+                       tcp_quench(tp->t_inpcb);
+                       return (0);
+               }
+               if ((error == EHOSTUNREACH || error == ENETDOWN)
+                   && TCPS_HAVERCVDSYN(tp->t_state)) {
+                       tp->t_softerror = error;
+                       return (0);
+               }
+               return (error);
+       }
+       tcpstat.tcps_sndtotal++;
+
+       /*
+        * Data sent (as far as we can tell).
+        * If this advertises a larger window than any other segment,
+        * then remember the size of the advertised window.
+        * Any pending ACK has now been sent.
+        */
+       if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
+               tp->rcv_adv = tp->rcv_nxt + win;
+       tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
+       if (sendalot)
+               goto again;
+       return (0);
+}
+
+tcp_setpersist(tp)
+       register struct tcpcb *tp;
+{
+       register t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
+
+       if (tp->t_timer[TCPT_REXMT])
+               panic("tcp_output REXMT");
+       /*
+        * Start/restart persistance timer.
+        */
+       TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],
+           t * tcp_backoff[tp->t_rxtshift],
+           TCPTV_PERSMIN, TCPTV_PERSMAX);
+       if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
+               tp->t_rxtshift++;
+}
diff --git a/usr/src/sys.386bsd/netinet/tcp_seq.h b/usr/src/sys.386bsd/netinet/tcp_seq.h
new file mode 100644 (file)
index 0000000..6b90e1a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_seq.h   7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * TCP sequence numbers are 32 bit integers operated
+ * on with modular arithmetic.  These macros can be
+ * used to compare such integers.
+ */
+#define        SEQ_LT(a,b)     ((int)((a)-(b)) < 0)
+#define        SEQ_LEQ(a,b)    ((int)((a)-(b)) <= 0)
+#define        SEQ_GT(a,b)     ((int)((a)-(b)) > 0)
+#define        SEQ_GEQ(a,b)    ((int)((a)-(b)) >= 0)
+
+/*
+ * Macros to initialize tcp sequence numbers for
+ * send and receive from initial send and receive
+ * sequence numbers.
+ */
+#define        tcp_rcvseqinit(tp) \
+       (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
+
+#define        tcp_sendseqinit(tp) \
+       (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
+           (tp)->iss
+
+#define        TCP_ISSINCR     (125*1024)      /* increment for tcp_iss each second */
+
+#ifdef KERNEL
+tcp_seq        tcp_iss;                /* tcp initial send seq # */
+#endif
diff --git a/usr/src/sys.386bsd/netinet/tcp_subr.c b/usr/src/sys.386bsd/netinet/tcp_subr.c
new file mode 100644 (file)
index 0000000..b2b1542
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_subr.c  7.20 (Berkeley) 12/1/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "protosw.h"
+#include "errno.h"
+
+#include "../net/route.h"
+#include "../net/if.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "ip_var.h"
+#include "ip_icmp.h"
+#include "tcp.h"
+#include "tcp_fsm.h"
+#include "tcp_seq.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+
+/* patchable/settable parameters for tcp */
+int    tcp_ttl = TCP_TTL;
+int    tcp_mssdflt = TCP_MSS;
+int    tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
+
+extern struct inpcb *tcp_last_inpcb;
+
+/*
+ * Tcp initialization
+ */
+tcp_init()
+{
+
+       tcp_iss = 1;            /* wrong */
+       tcb.inp_next = tcb.inp_prev = &tcb;
+       if (max_protohdr < sizeof(struct tcpiphdr))
+               max_protohdr = sizeof(struct tcpiphdr);
+       if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN)
+               panic("tcp_init");
+}
+
+/*
+ * Create template to be used to send tcp packets on a connection.
+ * Call after host entry created, allocates an mbuf and fills
+ * in a skeletal tcp/ip header, minimizing the amount of work
+ * necessary when the connection is used.
+ */
+struct tcpiphdr *
+tcp_template(tp)
+       struct tcpcb *tp;
+{
+       register struct inpcb *inp = tp->t_inpcb;
+       register struct mbuf *m;
+       register struct tcpiphdr *n;
+
+       if ((n = tp->t_template) == 0) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == NULL)
+                       return (0);
+               m->m_len = sizeof (struct tcpiphdr);
+               n = mtod(m, struct tcpiphdr *);
+       }
+       n->ti_next = n->ti_prev = 0;
+       n->ti_x1 = 0;
+       n->ti_pr = IPPROTO_TCP;
+       n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
+       n->ti_src = inp->inp_laddr;
+       n->ti_dst = inp->inp_faddr;
+       n->ti_sport = inp->inp_lport;
+       n->ti_dport = inp->inp_fport;
+       n->ti_seq = 0;
+       n->ti_ack = 0;
+       n->ti_x2 = 0;
+       n->ti_off = 5;
+       n->ti_flags = 0;
+       n->ti_win = 0;
+       n->ti_sum = 0;
+       n->ti_urp = 0;
+       return (n);
+}
+
+/*
+ * Send a single message to the TCP at address specified by
+ * the given TCP/IP header.  If m == 0, then we make a copy
+ * of the tcpiphdr at ti and send directly to the addressed host.
+ * This is used to force keep alive messages out using the TCP
+ * template for a connection tp->t_template.  If flags are given
+ * then we send a message back to the TCP which originated the
+ * segment ti, and discard the mbuf containing it and any other
+ * attached mbufs.
+ *
+ * In any case the ack and sequence number of the transmitted
+ * segment are as specified by the parameters.
+ */
+tcp_respond(tp, ti, m, ack, seq, flags)
+       struct tcpcb *tp;
+       register struct tcpiphdr *ti;
+       register struct mbuf *m;
+       tcp_seq ack, seq;
+       int flags;
+{
+       register int tlen;
+       int win = 0;
+       struct route *ro = 0;
+
+       if (tp) {
+               win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
+               ro = &tp->t_inpcb->inp_route;
+       }
+       if (m == 0) {
+               m = m_gethdr(M_DONTWAIT, MT_HEADER);
+               if (m == NULL)
+                       return;
+#ifdef TCP_COMPAT_42
+               tlen = 1;
+#else
+               tlen = 0;
+#endif
+               m->m_data += max_linkhdr;
+               *mtod(m, struct tcpiphdr *) = *ti;
+               ti = mtod(m, struct tcpiphdr *);
+               flags = TH_ACK;
+       } else {
+               m_freem(m->m_next);
+               m->m_next = 0;
+               m->m_data = (caddr_t)ti;
+               m->m_len = sizeof (struct tcpiphdr);
+               tlen = 0;
+#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
+               xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long);
+               xchg(ti->ti_dport, ti->ti_sport, u_short);
+#undef xchg
+       }
+       ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
+       tlen += sizeof (struct tcpiphdr);
+       m->m_len = tlen;
+       m->m_pkthdr.len = tlen;
+       m->m_pkthdr.rcvif = (struct ifnet *) 0;
+       ti->ti_next = ti->ti_prev = 0;
+       ti->ti_x1 = 0;
+       ti->ti_seq = htonl(seq);
+       ti->ti_ack = htonl(ack);
+       ti->ti_x2 = 0;
+       ti->ti_off = sizeof (struct tcphdr) >> 2;
+       ti->ti_flags = flags;
+       ti->ti_win = htons((u_short)win);
+       ti->ti_urp = 0;
+       ti->ti_sum = in_cksum(m, tlen);
+       ((struct ip *)ti)->ip_len = tlen;
+       ((struct ip *)ti)->ip_ttl = tcp_ttl;
+       (void) ip_output(m, (struct mbuf *)0, ro, 0);
+}
+
+/*
+ * Create a new TCP control block, making an
+ * empty reassembly queue and hooking it to the argument
+ * protocol control block.
+ */
+struct tcpcb *
+tcp_newtcpcb(inp)
+       struct inpcb *inp;
+{
+       struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
+       register struct tcpcb *tp;
+
+       if (m == NULL)
+               return ((struct tcpcb *)0);
+       tp = mtod(m, struct tcpcb *);
+       tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
+       tp->t_maxseg = tcp_mssdflt;
+
+       tp->t_flags = 0;                /* sends options! */
+       tp->t_inpcb = inp;
+       /*
+        * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
+        * rtt estimate.  Set rttvar so that srtt + 2 * rttvar gives
+        * reasonable initial retransmit time.
+        */
+       tp->t_srtt = TCPTV_SRTTBASE;
+       tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
+       tp->t_rttmin = TCPTV_MIN;
+       TCPT_RANGESET(tp->t_rxtcur, 
+           ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
+           TCPTV_MIN, TCPTV_REXMTMAX);
+       tp->snd_cwnd = TCP_MAXWIN;
+       tp->snd_ssthresh = TCP_MAXWIN;
+       inp->inp_ip.ip_ttl = tcp_ttl;
+       inp->inp_ppcb = (caddr_t)tp;
+       return (tp);
+}
+
+/*
+ * Drop a TCP connection, reporting
+ * the specified error.  If connection is synchronized,
+ * then send a RST to peer.
+ */
+struct tcpcb *
+tcp_drop(tp, errno)
+       register struct tcpcb *tp;
+       int errno;
+{
+       struct socket *so = tp->t_inpcb->inp_socket;
+
+       if (TCPS_HAVERCVDSYN(tp->t_state)) {
+               tp->t_state = TCPS_CLOSED;
+               (void) tcp_output(tp);
+               tcpstat.tcps_drops++;
+       } else
+               tcpstat.tcps_conndrops++;
+       if (errno == ETIMEDOUT && tp->t_softerror)
+               errno = tp->t_softerror;
+       so->so_error = errno;
+       return (tcp_close(tp));
+}
+
+/*
+ * Close a TCP control block:
+ *     discard all space held by the tcp
+ *     discard internet protocol block
+ *     wake up any sleepers
+ */
+struct tcpcb *
+tcp_close(tp)
+       register struct tcpcb *tp;
+{
+       register struct tcpiphdr *t;
+       struct inpcb *inp = tp->t_inpcb;
+       struct socket *so = inp->inp_socket;
+       register struct mbuf *m;
+#ifdef RTV_RTT
+       register struct rtentry *rt;
+
+       /*
+        * If we sent enough data to get some meaningful characteristics,
+        * save them in the routing entry.  'Enough' is arbitrarily 
+        * defined as the sendpipesize (default 4K) * 16.  This would
+        * give us 16 rtt samples assuming we only get one sample per
+        * window (the usual case on a long haul net).  16 samples is
+        * enough for the srtt filter to converge to within 5% of the correct
+        * value; fewer samples and we could save a very bogus rtt.
+        *
+        * Don't update the default route's characteristics and don't
+        * update anything that the user "locked".
+        */
+       if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) &&
+           (rt = inp->inp_route.ro_rt) &&
+           ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) {
+               register u_long i;
+
+               if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) {
+                       i = tp->t_srtt *
+                           (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
+                       if (rt->rt_rmx.rmx_rtt && i)
+                               /*
+                                * filter this update to half the old & half
+                                * the new values, converting scale.
+                                * See route.h and tcp_var.h for a
+                                * description of the scaling constants.
+                                */
+                               rt->rt_rmx.rmx_rtt =
+                                   (rt->rt_rmx.rmx_rtt + i) / 2;
+                       else
+                               rt->rt_rmx.rmx_rtt = i;
+               }
+               if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) {
+                       i = tp->t_rttvar *
+                           (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
+                       if (rt->rt_rmx.rmx_rttvar && i)
+                               rt->rt_rmx.rmx_rttvar =
+                                   (rt->rt_rmx.rmx_rttvar + i) / 2;
+                       else
+                               rt->rt_rmx.rmx_rttvar = i;
+               }
+               /*
+                * update the pipelimit (ssthresh) if it has been updated
+                * already or if a pipesize was specified & the threshhold
+                * got below half the pipesize.  I.e., wait for bad news
+                * before we start updating, then update on both good
+                * and bad news.
+                */
+               if ((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 &&
+                   (i = tp->snd_ssthresh) && rt->rt_rmx.rmx_ssthresh ||
+                   i < (rt->rt_rmx.rmx_sendpipe / 2)) {
+                       /*
+                        * convert the limit from user data bytes to
+                        * packets then to packet data bytes.
+                        */
+                       i = (i + tp->t_maxseg / 2) / tp->t_maxseg;
+                       if (i < 2)
+                               i = 2;
+                       i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr));
+                       if (rt->rt_rmx.rmx_ssthresh)
+                               rt->rt_rmx.rmx_ssthresh =
+                                   (rt->rt_rmx.rmx_ssthresh + i) / 2;
+                       else
+                               rt->rt_rmx.rmx_ssthresh = i;
+               }
+       }
+#endif RTV_RTT
+       /* free the reassembly queue, if any */
+       t = tp->seg_next;
+       while (t != (struct tcpiphdr *)tp) {
+               t = (struct tcpiphdr *)t->ti_next;
+               m = REASS_MBUF((struct tcpiphdr *)t->ti_prev);
+               remque(t->ti_prev);
+               m_freem(m);
+       }
+       if (tp->t_template)
+               (void) m_free(dtom(tp->t_template));
+       (void) m_free(dtom(tp));
+       inp->inp_ppcb = 0;
+       soisdisconnected(so);
+       /* clobber input pcb cache if we're closing the cached connection */
+       if (inp == tcp_last_inpcb)
+               tcp_last_inpcb = &tcb;
+       in_pcbdetach(inp);
+       tcpstat.tcps_closed++;
+       return ((struct tcpcb *)0);
+}
+
+tcp_drain()
+{
+
+}
+
+/*
+ * Notify a tcp user of an asynchronous error;
+ * store error as soft error, but wake up user
+ * (for now, won't do anything until can select for soft error).
+ */
+tcp_notify(inp, error)
+       register struct inpcb *inp;
+       int error;
+{
+
+       ((struct tcpcb *)inp->inp_ppcb)->t_softerror = error;
+       wakeup((caddr_t) &inp->inp_socket->so_timeo);
+       sorwakeup(inp->inp_socket);
+       sowwakeup(inp->inp_socket);
+}
+
+tcp_ctlinput(cmd, sa, ip)
+       int cmd;
+       struct sockaddr *sa;
+       register struct ip *ip;
+{
+       register struct tcphdr *th;
+       extern struct in_addr zeroin_addr;
+       extern u_char inetctlerrmap[];
+       int (*notify)() = tcp_notify, tcp_quench();
+
+       if (cmd == PRC_QUENCH)
+               notify = tcp_quench;
+       else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
+               return;
+       if (ip) {
+               th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+               in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
+                       cmd, notify);
+       } else
+               in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
+}
+
+/*
+ * When a source quench is received, close congestion window
+ * to one segment.  We will gradually open it again as we proceed.
+ */
+tcp_quench(inp)
+       struct inpcb *inp;
+{
+       struct tcpcb *tp = intotcpcb(inp);
+
+       if (tp)
+               tp->snd_cwnd = tp->t_maxseg;
+}
diff --git a/usr/src/sys.386bsd/netinet/tcp_timer.c b/usr/src/sys.386bsd/netinet/tcp_timer.c
new file mode 100644 (file)
index 0000000..e372e36
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_timer.c 7.18 (Berkeley) 6/28/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "protosw.h"
+#include "errno.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "ip_var.h"
+#include "tcp.h"
+#include "tcp_fsm.h"
+#include "tcp_seq.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+
+int    tcp_keepidle = TCPTV_KEEP_IDLE;
+int    tcp_keepintvl = TCPTV_KEEPINTVL;
+int    tcp_maxidle;
+/*
+ * Fast timeout routine for processing delayed acks
+ */
+tcp_fasttimo()
+{
+       register struct inpcb *inp;
+       register struct tcpcb *tp;
+       int s = splnet();
+
+       inp = tcb.inp_next;
+       if (inp)
+       for (; inp != &tcb; inp = inp->inp_next)
+               if ((tp = (struct tcpcb *)inp->inp_ppcb) &&
+                   (tp->t_flags & TF_DELACK)) {
+                       tp->t_flags &= ~TF_DELACK;
+                       tp->t_flags |= TF_ACKNOW;
+                       tcpstat.tcps_delack++;
+                       (void) tcp_output(tp);
+               }
+       splx(s);
+}
+
+/*
+ * Tcp protocol timeout routine called every 500 ms.
+ * Updates the timers in all active tcb's and
+ * causes finite state machine actions if timers expire.
+ */
+tcp_slowtimo()
+{
+       register struct inpcb *ip, *ipnxt;
+       register struct tcpcb *tp;
+       int s = splnet();
+       register int i;
+
+       tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
+       /*
+        * Search through tcb's and update active timers.
+        */
+       ip = tcb.inp_next;
+       if (ip == 0) {
+               splx(s);
+               return;
+       }
+       for (; ip != &tcb; ip = ipnxt) {
+               ipnxt = ip->inp_next;
+               tp = intotcpcb(ip);
+               if (tp == 0)
+                       continue;
+               for (i = 0; i < TCPT_NTIMERS; i++) {
+                       if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
+                               (void) tcp_usrreq(tp->t_inpcb->inp_socket,
+                                   PRU_SLOWTIMO, (struct mbuf *)0,
+                                   (struct mbuf *)i, (struct mbuf *)0);
+                               if (ipnxt->inp_prev != ip)
+                                       goto tpgone;
+                       }
+               }
+               tp->t_idle++;
+               if (tp->t_rtt)
+                       tp->t_rtt++;
+tpgone:
+               ;
+       }
+       tcp_iss += TCP_ISSINCR/PR_SLOWHZ;               /* increment iss */
+#ifdef TCP_COMPAT_42
+       if ((int)tcp_iss < 0)
+               tcp_iss = 0;                            /* XXX */
+#endif
+       splx(s);
+}
+
+/*
+ * Cancel all timers for TCP tp.
+ */
+tcp_canceltimers(tp)
+       struct tcpcb *tp;
+{
+       register int i;
+
+       for (i = 0; i < TCPT_NTIMERS; i++)
+               tp->t_timer[i] = 0;
+}
+
+int    tcp_backoff[TCP_MAXRXTSHIFT + 1] =
+    { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
+
+/*
+ * TCP timer processing.
+ */
+struct tcpcb *
+tcp_timers(tp, timer)
+       register struct tcpcb *tp;
+       int timer;
+{
+       register int rexmt;
+
+       switch (timer) {
+
+       /*
+        * 2 MSL timeout in shutdown went off.  If we're closed but
+        * still waiting for peer to close and connection has been idle
+        * too long, or if 2MSL time is up from TIME_WAIT, delete connection
+        * control block.  Otherwise, check again in a bit.
+        */
+       case TCPT_2MSL:
+               if (tp->t_state != TCPS_TIME_WAIT &&
+                   tp->t_idle <= tcp_maxidle)
+                       tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
+               else
+                       tp = tcp_close(tp);
+               break;
+
+       /*
+        * Retransmission timer went off.  Message has not
+        * been acked within retransmit interval.  Back off
+        * to a longer retransmit interval and retransmit one segment.
+        */
+       case TCPT_REXMT:
+               if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
+                       tp->t_rxtshift = TCP_MAXRXTSHIFT;
+                       tcpstat.tcps_timeoutdrop++;
+                       tp = tcp_drop(tp, tp->t_softerror ?
+                           tp->t_softerror : ETIMEDOUT);
+                       break;
+               }
+               tcpstat.tcps_rexmttimeo++;
+               rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
+               TCPT_RANGESET(tp->t_rxtcur, rexmt,
+                   tp->t_rttmin, TCPTV_REXMTMAX);
+               tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
+               /*
+                * If losing, let the lower level know and try for
+                * a better route.  Also, if we backed off this far,
+                * our srtt estimate is probably bogus.  Clobber it
+                * so we'll take the next rtt measurement as our srtt;
+                * move the current srtt into rttvar to keep the current
+                * retransmit times until then.
+                */
+               if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
+                       in_losing(tp->t_inpcb);
+                       tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
+                       tp->t_srtt = 0;
+               }
+               tp->snd_nxt = tp->snd_una;
+               /*
+                * If timing a segment in this window, stop the timer.
+                */
+               tp->t_rtt = 0;
+               /*
+                * Close the congestion window down to one segment
+                * (we'll open it by one segment for each ack we get).
+                * Since we probably have a window's worth of unacked
+                * data accumulated, this "slow start" keeps us from
+                * dumping all that data as back-to-back packets (which
+                * might overwhelm an intermediate gateway).
+                *
+                * There are two phases to the opening: Initially we
+                * open by one mss on each ack.  This makes the window
+                * size increase exponentially with time.  If the
+                * window is larger than the path can handle, this
+                * exponential growth results in dropped packet(s)
+                * almost immediately.  To get more time between 
+                * drops but still "push" the network to take advantage
+                * of improving conditions, we switch from exponential
+                * to linear window opening at some threshhold size.
+                * For a threshhold, we use half the current window
+                * size, truncated to a multiple of the mss.
+                *
+                * (the minimum cwnd that will give us exponential
+                * growth is 2 mss.  We don't allow the threshhold
+                * to go below this.)
+                */
+               {
+               u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
+               if (win < 2)
+                       win = 2;
+               tp->snd_cwnd = tp->t_maxseg;
+               tp->snd_ssthresh = win * tp->t_maxseg;
+               tp->t_dupacks = 0;
+               }
+               (void) tcp_output(tp);
+               break;
+
+       /*
+        * Persistance timer into zero window.
+        * Force a byte to be output, if possible.
+        */
+       case TCPT_PERSIST:
+               tcpstat.tcps_persisttimeo++;
+               tcp_setpersist(tp);
+               tp->t_force = 1;
+               (void) tcp_output(tp);
+               tp->t_force = 0;
+               break;
+
+       /*
+        * Keep-alive timer went off; send something
+        * or drop connection if idle for too long.
+        */
+       case TCPT_KEEP:
+               tcpstat.tcps_keeptimeo++;
+               if (tp->t_state < TCPS_ESTABLISHED)
+                       goto dropit;
+               if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE &&
+                   tp->t_state <= TCPS_CLOSE_WAIT) {
+                       if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
+                               goto dropit;
+                       /*
+                        * Send a packet designed to force a response
+                        * if the peer is up and reachable:
+                        * either an ACK if the connection is still alive,
+                        * or an RST if the peer has closed the connection
+                        * due to timeout or reboot.
+                        * Using sequence number tp->snd_una-1
+                        * causes the transmitted zero-length segment
+                        * to lie outside the receive window;
+                        * by the protocol spec, this requires the
+                        * correspondent TCP to respond.
+                        */
+                       tcpstat.tcps_keepprobe++;
+#ifdef TCP_COMPAT_42
+                       /*
+                        * The keepalive packet must have nonzero length
+                        * to get a 4.2 host to respond.
+                        */
+                       tcp_respond(tp, tp->t_template, (struct mbuf *)NULL,
+                           tp->rcv_nxt - 1, tp->snd_una - 1, 0);
+#else
+                       tcp_respond(tp, tp->t_template, (struct mbuf *)NULL,
+                           tp->rcv_nxt, tp->snd_una - 1, 0);
+#endif
+                       tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
+               } else
+                       tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+               break;
+       dropit:
+               tcpstat.tcps_keepdrops++;
+               tp = tcp_drop(tp, ETIMEDOUT);
+               break;
+       }
+       return (tp);
+}
diff --git a/usr/src/sys.386bsd/netinet/tcp_timer.h b/usr/src/sys.386bsd/netinet/tcp_timer.h
new file mode 100644 (file)
index 0000000..095be43
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_timer.h 7.8 (Berkeley) 6/28/90
+ */
+
+/*
+ * Definitions of the TCP timers.  These timers are counted
+ * down PR_SLOWHZ times a second.
+ */
+#define        TCPT_NTIMERS    4
+
+#define        TCPT_REXMT      0               /* retransmit */
+#define        TCPT_PERSIST    1               /* retransmit persistance */
+#define        TCPT_KEEP       2               /* keep alive */
+#define        TCPT_2MSL       3               /* 2*msl quiet time timer */
+
+/*
+ * The TCPT_REXMT timer is used to force retransmissions.
+ * The TCP has the TCPT_REXMT timer set whenever segments
+ * have been sent for which ACKs are expected but not yet
+ * received.  If an ACK is received which advances tp->snd_una,
+ * then the retransmit timer is cleared (if there are no more
+ * outstanding segments) or reset to the base value (if there
+ * are more ACKs expected).  Whenever the retransmit timer goes off,
+ * we retransmit one unacknowledged segment, and do a backoff
+ * on the retransmit timer.
+ *
+ * The TCPT_PERSIST timer is used to keep window size information
+ * flowing even if the window goes shut.  If all previous transmissions
+ * have been acknowledged (so that there are no retransmissions in progress),
+ * and the window is too small to bother sending anything, then we start
+ * the TCPT_PERSIST timer.  When it expires, if the window is nonzero,
+ * we go to transmit state.  Otherwise, at intervals send a single byte
+ * into the peer's window to force him to update our window information.
+ * We do this at most as often as TCPT_PERSMIN time intervals,
+ * but no more frequently than the current estimate of round-trip
+ * packet time.  The TCPT_PERSIST timer is cleared whenever we receive
+ * a window update from the peer.
+ *
+ * The TCPT_KEEP timer is used to keep connections alive.  If an
+ * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
+ * but not yet established, then we drop the connection.  Once the connection
+ * is established, if the connection is idle for TCPTV_KEEP_IDLE time
+ * (and keepalives have been enabled on the socket), we begin to probe
+ * the connection.  We force the peer to send us a segment by sending:
+ *     <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
+ * This segment is (deliberately) outside the window, and should elicit
+ * an ack segment in response from the peer.  If, despite the TCPT_KEEP
+ * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
+ * amount of time probing, then we drop the connection.
+ */
+
+#define        TCP_TTL         60              /* default time to live for TCP segs */
+/*
+ * Time constants.
+ */
+#define        TCPTV_MSL       ( 30*PR_SLOWHZ)         /* max seg lifetime (hah!) */
+#define        TCPTV_SRTTBASE  0                       /* base roundtrip time;
+                                                  if 0, no idea yet */
+#define        TCPTV_SRTTDFLT  (  3*PR_SLOWHZ)         /* assumed RTT if no info */
+
+#define        TCPTV_PERSMIN   (  5*PR_SLOWHZ)         /* retransmit persistance */
+#define        TCPTV_PERSMAX   ( 60*PR_SLOWHZ)         /* maximum persist interval */
+
+#define        TCPTV_KEEP_INIT ( 75*PR_SLOWHZ)         /* initial connect keep alive */
+#define        TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ)      /* dflt time before probing */
+#define        TCPTV_KEEPINTVL ( 75*PR_SLOWHZ)         /* default probe interval */
+#define        TCPTV_KEEPCNT   8                       /* max probes before drop */
+
+#define        TCPTV_MIN       (  1*PR_SLOWHZ)         /* minimum allowable value */
+#define        TCPTV_REXMTMAX  ( 64*PR_SLOWHZ)         /* max allowable REXMT value */
+
+#define        TCP_LINGERTIME  120                     /* linger at most 2 minutes */
+
+#define        TCP_MAXRXTSHIFT 12                      /* maximum retransmits */
+
+#ifdef TCPTIMERS
+char *tcptimers[] =
+    { "REXMT", "PERSIST", "KEEP", "2MSL" };
+#endif
+
+/*
+ * Force a time value to be in a certain range.
+ */
+#define        TCPT_RANGESET(tv, value, tvmin, tvmax) { \
+       (tv) = (value); \
+       if ((tv) < (tvmin)) \
+               (tv) = (tvmin); \
+       else if ((tv) > (tvmax)) \
+               (tv) = (tvmax); \
+}
+
+#ifdef KERNEL
+extern int tcp_keepidle;               /* time before keepalive probes begin */
+extern int tcp_keepintvl;              /* time between keepalive probes */
+extern int tcp_maxidle;                        /* time to drop after starting probes */
+extern int tcp_ttl;                    /* time to live for TCP segs */
+extern int tcp_backoff[];
+#endif
diff --git a/usr/src/sys.386bsd/netinet/tcp_usrreq.c b/usr/src/sys.386bsd/netinet/tcp_usrreq.c
new file mode 100644 (file)
index 0000000..317828a
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_usrreq.c        7.15 (Berkeley) 6/28/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "protosw.h"
+#include "errno.h"
+#include "stat.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "ip_var.h"
+#include "tcp.h"
+#include "tcp_fsm.h"
+#include "tcp_seq.h"
+#include "tcp_timer.h"
+#include "tcp_var.h"
+#include "tcpip.h"
+#include "tcp_debug.h"
+
+/*
+ * TCP protocol interface to socket abstraction.
+ */
+extern char *tcpstates[];
+struct tcpcb *tcp_newtcpcb();
+
+/*
+ * Process a TCP user request for TCP tb.  If this is a send request
+ * then m is the mbuf chain of send data.  If this is a timer expiration
+ * (called from the software clock routine), then timertype tells which timer.
+ */
+/*ARGSUSED*/
+tcp_usrreq(so, req, m, nam, control)
+       struct socket *so;
+       int req;
+       struct mbuf *m, *nam, *control;
+{
+       register struct inpcb *inp;
+       register struct tcpcb *tp;
+       int s;
+       int error = 0;
+       int ostate;
+
+       if (req == PRU_CONTROL)
+               return (in_control(so, (int)m, (caddr_t)nam,
+                       (struct ifnet *)control));
+       if (control && control->m_len) {
+               m_freem(control);
+               if (m)
+                       m_freem(m);
+               return (EINVAL);
+       }
+
+       s = splnet();
+       inp = sotoinpcb(so);
+       /*
+        * When a TCP is attached to a socket, then there will be
+        * a (struct inpcb) pointed at by the socket, and this
+        * structure will point at a subsidary (struct tcpcb).
+        */
+       if (inp == 0 && req != PRU_ATTACH) {
+               splx(s);
+               return (EINVAL);                /* XXX */
+       }
+       if (inp) {
+               tp = intotcpcb(inp);
+               /* WHAT IF TP IS 0? */
+#ifdef KPROF
+               tcp_acounts[tp->t_state][req]++;
+#endif
+               ostate = tp->t_state;
+       } else
+               ostate = 0;
+       switch (req) {
+
+       /*
+        * TCP attaches to socket via PRU_ATTACH, reserving space,
+        * and an internet control block.
+        */
+       case PRU_ATTACH:
+               if (inp) {
+                       error = EISCONN;
+                       break;
+               }
+               error = tcp_attach(so);
+               if (error)
+                       break;
+               if ((so->so_options & SO_LINGER) && so->so_linger == 0)
+                       so->so_linger = TCP_LINGERTIME;
+               tp = sototcpcb(so);
+               break;
+
+       /*
+        * PRU_DETACH detaches the TCP protocol from the socket.
+        * If the protocol state is non-embryonic, then can't
+        * do this directly: have to initiate a PRU_DISCONNECT,
+        * which may finish later; embryonic TCB's can just
+        * be discarded here.
+        */
+       case PRU_DETACH:
+               if (tp->t_state > TCPS_LISTEN)
+                       tp = tcp_disconnect(tp);
+               else
+                       tp = tcp_close(tp);
+               break;
+
+       /*
+        * Give the socket an address.
+        */
+       case PRU_BIND:
+               error = in_pcbbind(inp, nam);
+               if (error)
+                       break;
+               break;
+
+       /*
+        * Prepare to accept connections.
+        */
+       case PRU_LISTEN:
+               if (inp->inp_lport == 0)
+                       error = in_pcbbind(inp, (struct mbuf *)0);
+               if (error == 0)
+                       tp->t_state = TCPS_LISTEN;
+               break;
+
+       /*
+        * Initiate connection to peer.
+        * Create a template for use in transmissions on this connection.
+        * Enter SYN_SENT state, and mark socket as connecting.
+        * Start keep-alive timer, and seed output sequence space.
+        * Send initial segment on connection.
+        */
+       case PRU_CONNECT:
+               if (inp->inp_lport == 0) {
+                       error = in_pcbbind(inp, (struct mbuf *)0);
+                       if (error)
+                               break;
+               }
+               error = in_pcbconnect(inp, nam);
+               if (error)
+                       break;
+               tp->t_template = tcp_template(tp);
+               if (tp->t_template == 0) {
+                       in_pcbdisconnect(inp);
+                       error = ENOBUFS;
+                       break;
+               }
+               soisconnecting(so);
+               tcpstat.tcps_connattempt++;
+               tp->t_state = TCPS_SYN_SENT;
+               tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+               tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
+               tcp_sendseqinit(tp);
+               error = tcp_output(tp);
+               break;
+
+       /*
+        * Create a TCP connection between two sockets.
+        */
+       case PRU_CONNECT2:
+               error = EOPNOTSUPP;
+               break;
+
+       /*
+        * Initiate disconnect from peer.
+        * If connection never passed embryonic stage, just drop;
+        * else if don't need to let data drain, then can just drop anyways,
+        * else have to begin TCP shutdown process: mark socket disconnecting,
+        * drain unread data, state switch to reflect user close, and
+        * send segment (e.g. FIN) to peer.  Socket will be really disconnected
+        * when peer sends FIN and acks ours.
+        *
+        * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
+        */
+       case PRU_DISCONNECT:
+               tp = tcp_disconnect(tp);
+               break;
+
+       /*
+        * Accept a connection.  Essentially all the work is
+        * done at higher levels; just return the address
+        * of the peer, storing through addr.
+        */
+       case PRU_ACCEPT: {
+               struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+
+               nam->m_len = sizeof (struct sockaddr_in);
+               sin->sin_family = AF_INET;
+               sin->sin_len = sizeof(*sin);
+               sin->sin_port = inp->inp_fport;
+               sin->sin_addr = inp->inp_faddr;
+               break;
+               }
+
+       /*
+        * Mark the connection as being incapable of further output.
+        */
+       case PRU_SHUTDOWN:
+               socantsendmore(so);
+               tp = tcp_usrclosed(tp);
+               if (tp)
+                       error = tcp_output(tp);
+               break;
+
+       /*
+        * After a receive, possibly send window update to peer.
+        */
+       case PRU_RCVD:
+               (void) tcp_output(tp);
+               break;
+
+       /*
+        * Do a send by putting data in output queue and updating urgent
+        * marker if URG set.  Possibly send more data.
+        */
+       case PRU_SEND:
+               sbappend(&so->so_snd, m);
+               error = tcp_output(tp);
+               break;
+
+       /*
+        * Abort the TCP.
+        */
+       case PRU_ABORT:
+               tp = tcp_drop(tp, ECONNABORTED);
+               break;
+
+       case PRU_SENSE:
+               ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
+               (void) splx(s);
+               return (0);
+
+       case PRU_RCVOOB:
+               if ((so->so_oobmark == 0 &&
+                   (so->so_state & SS_RCVATMARK) == 0) ||
+                   so->so_options & SO_OOBINLINE ||
+                   tp->t_oobflags & TCPOOB_HADDATA) {
+                       error = EINVAL;
+                       break;
+               }
+               if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
+                       error = EWOULDBLOCK;
+                       break;
+               }
+               m->m_len = 1;
+               *mtod(m, caddr_t) = tp->t_iobc;
+               if (((int)nam & MSG_PEEK) == 0)
+                       tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
+               break;
+
+       case PRU_SENDOOB:
+               if (sbspace(&so->so_snd) < -512) {
+                       m_freem(m);
+                       error = ENOBUFS;
+                       break;
+               }
+               /*
+                * According to RFC961 (Assigned Protocols),
+                * the urgent pointer points to the last octet
+                * of urgent data.  We continue, however,
+                * to consider it to indicate the first octet
+                * of data past the urgent section.
+                * Otherwise, snd_up should be one lower.
+                */
+               sbappend(&so->so_snd, m);
+               tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
+               tp->t_force = 1;
+               error = tcp_output(tp);
+               tp->t_force = 0;
+               break;
+
+       case PRU_SOCKADDR:
+               in_setsockaddr(inp, nam);
+               break;
+
+       case PRU_PEERADDR:
+               in_setpeeraddr(inp, nam);
+               break;
+
+       /*
+        * TCP slow timer went off; going through this
+        * routine for tracing's sake.
+        */
+       case PRU_SLOWTIMO:
+               tp = tcp_timers(tp, (int)nam);
+               req |= (int)nam << 8;           /* for debug's sake */
+               break;
+
+       default:
+               panic("tcp_usrreq");
+       }
+       if (tp && (so->so_options & SO_DEBUG))
+               tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
+       splx(s);
+       return (error);
+}
+
+tcp_ctloutput(op, so, level, optname, mp)
+       int op;
+       struct socket *so;
+       int level, optname;
+       struct mbuf **mp;
+{
+       int error = 0;
+       struct inpcb *inp = sotoinpcb(so);
+       register struct tcpcb *tp = intotcpcb(inp);
+       register struct mbuf *m;
+
+       if (level != IPPROTO_TCP)
+               return (ip_ctloutput(op, so, level, optname, mp));
+
+       switch (op) {
+
+       case PRCO_SETOPT:
+               m = *mp;
+               switch (optname) {
+
+               case TCP_NODELAY:
+                       if (m == NULL || m->m_len < sizeof (int))
+                               error = EINVAL;
+                       else if (*mtod(m, int *))
+                               tp->t_flags |= TF_NODELAY;
+                       else
+                               tp->t_flags &= ~TF_NODELAY;
+                       break;
+
+               case TCP_MAXSEG:        /* not yet */
+               default:
+                       error = EINVAL;
+                       break;
+               }
+               if (m)
+                       (void) m_free(m);
+               break;
+
+       case PRCO_GETOPT:
+               *mp = m = m_get(M_WAIT, MT_SOOPTS);
+               m->m_len = sizeof(int);
+
+               switch (optname) {
+               case TCP_NODELAY:
+                       *mtod(m, int *) = tp->t_flags & TF_NODELAY;
+                       break;
+               case TCP_MAXSEG:
+                       *mtod(m, int *) = tp->t_maxseg;
+                       break;
+               default:
+                       error = EINVAL;
+                       break;
+               }
+               break;
+       }
+       return (error);
+}
+
+u_long tcp_sendspace = 1024*4;
+u_long tcp_recvspace = 1024*4;
+
+/*
+ * Attach TCP protocol to socket, allocating
+ * internet protocol control block, tcp control block,
+ * bufer space, and entering LISTEN state if to accept connections.
+ */
+tcp_attach(so)
+       struct socket *so;
+{
+       register struct tcpcb *tp;
+       struct inpcb *inp;
+       int error;
+
+       if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
+               error = soreserve(so, tcp_sendspace, tcp_recvspace);
+               if (error)
+                       return (error);
+       }
+       error = in_pcballoc(so, &tcb);
+       if (error)
+               return (error);
+       inp = sotoinpcb(so);
+       tp = tcp_newtcpcb(inp);
+       if (tp == 0) {
+               int nofd = so->so_state & SS_NOFDREF;   /* XXX */
+
+               so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
+               in_pcbdetach(inp);
+               so->so_state |= nofd;
+               return (ENOBUFS);
+       }
+       tp->t_state = TCPS_CLOSED;
+       return (0);
+}
+
+/*
+ * Initiate (or continue) disconnect.
+ * If embryonic state, just send reset (once).
+ * If in ``let data drain'' option and linger null, just drop.
+ * Otherwise (hard), mark socket disconnecting and drop
+ * current input data; switch states based on user close, and
+ * send segment to peer (with FIN).
+ */
+struct tcpcb *
+tcp_disconnect(tp)
+       register struct tcpcb *tp;
+{
+       struct socket *so = tp->t_inpcb->inp_socket;
+
+       if (tp->t_state < TCPS_ESTABLISHED)
+               tp = tcp_close(tp);
+       else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
+               tp = tcp_drop(tp, 0);
+       else {
+               soisdisconnecting(so);
+               sbflush(&so->so_rcv);
+               tp = tcp_usrclosed(tp);
+               if (tp)
+                       (void) tcp_output(tp);
+       }
+       return (tp);
+}
+
+/*
+ * User issued close, and wish to trail through shutdown states:
+ * if never received SYN, just forget it.  If got a SYN from peer,
+ * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
+ * If already got a FIN from peer, then almost done; go to LAST_ACK
+ * state.  In all other cases, have already sent FIN to peer (e.g.
+ * after PRU_SHUTDOWN), and just have to play tedious game waiting
+ * for peer to send FIN or not respond to keep-alives, etc.
+ * We can let the user exit from the close as soon as the FIN is acked.
+ */
+struct tcpcb *
+tcp_usrclosed(tp)
+       register struct tcpcb *tp;
+{
+
+       switch (tp->t_state) {
+
+       case TCPS_CLOSED:
+       case TCPS_LISTEN:
+       case TCPS_SYN_SENT:
+               tp->t_state = TCPS_CLOSED;
+               tp = tcp_close(tp);
+               break;
+
+       case TCPS_SYN_RECEIVED:
+       case TCPS_ESTABLISHED:
+               tp->t_state = TCPS_FIN_WAIT_1;
+               break;
+
+       case TCPS_CLOSE_WAIT:
+               tp->t_state = TCPS_LAST_ACK;
+               break;
+       }
+       if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
+               soisdisconnected(tp->t_inpcb->inp_socket);
+       return (tp);
+}
diff --git a/usr/src/sys.386bsd/netinet/tcp_var.h b/usr/src/sys.386bsd/netinet/tcp_var.h
new file mode 100644 (file)
index 0000000..0f04c38
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_var.h   7.10 (Berkeley) 6/28/90
+ */
+
+/*
+ * Kernel variables for tcp.
+ */
+
+/*
+ * Tcp control block, one per tcp; fields:
+ */
+struct tcpcb {
+       struct  tcpiphdr *seg_next;     /* sequencing queue */
+       struct  tcpiphdr *seg_prev;
+       short   t_state;                /* state of this connection */
+       short   t_timer[TCPT_NTIMERS];  /* tcp timers */
+       short   t_rxtshift;             /* log(2) of rexmt exp. backoff */
+       short   t_rxtcur;               /* current retransmit value */
+       short   t_dupacks;              /* consecutive dup acks recd */
+       u_short t_maxseg;               /* maximum segment size */
+       char    t_force;                /* 1 if forcing out a byte */
+       u_char  t_flags;
+#define        TF_ACKNOW       0x01            /* ack peer immediately */
+#define        TF_DELACK       0x02            /* ack, but try to delay it */
+#define        TF_NODELAY      0x04            /* don't delay packets to coalesce */
+#define        TF_NOOPT        0x08            /* don't use tcp options */
+#define        TF_SENTFIN      0x10            /* have sent FIN */
+       struct  tcpiphdr *t_template;   /* skeletal packet for transmit */
+       struct  inpcb *t_inpcb;         /* back pointer to internet pcb */
+/*
+ * The following fields are used as in the protocol specification.
+ * See RFC783, Dec. 1981, page 21.
+ */
+/* send sequence variables */
+       tcp_seq snd_una;                /* send unacknowledged */
+       tcp_seq snd_nxt;                /* send next */
+       tcp_seq snd_up;                 /* send urgent pointer */
+       tcp_seq snd_wl1;                /* window update seg seq number */
+       tcp_seq snd_wl2;                /* window update seg ack number */
+       tcp_seq iss;                    /* initial send sequence number */
+       u_short snd_wnd;                /* send window */
+/* receive sequence variables */
+       u_short rcv_wnd;                /* receive window */
+       tcp_seq rcv_nxt;                /* receive next */
+       tcp_seq rcv_up;                 /* receive urgent pointer */
+       tcp_seq irs;                    /* initial receive sequence number */
+/*
+ * Additional variables for this implementation.
+ */
+/* receive variables */
+       tcp_seq rcv_adv;                /* advertised window */
+/* retransmit variables */
+       tcp_seq snd_max;                /* highest sequence number sent;
+                                        * used to recognize retransmits
+                                        */
+/* congestion control (for slow start, source quench, retransmit after loss) */
+       u_short snd_cwnd;               /* congestion-controlled window */
+       u_short snd_ssthresh;           /* snd_cwnd size threshhold for
+                                        * for slow start exponential to
+                                        * linear switch
+                                        */
+/*
+ * transmit timing stuff.  See below for scale of srtt and rttvar.
+ * "Variance" is actually smoothed difference.
+ */
+       short   t_idle;                 /* inactivity time */
+       short   t_rtt;                  /* round trip time */
+       tcp_seq t_rtseq;                /* sequence number being timed */
+       short   t_srtt;                 /* smoothed round-trip time */
+       short   t_rttvar;               /* variance in round-trip time */
+       u_short t_rttmin;               /* minimum rtt allowed */
+       u_short max_sndwnd;             /* largest window peer has offered */
+
+/* out-of-band data */
+       char    t_oobflags;             /* have some */
+       char    t_iobc;                 /* input character */
+#define        TCPOOB_HAVEDATA 0x01
+#define        TCPOOB_HADDATA  0x02
+       short   t_softerror;            /* possible error not yet reported */
+};
+
+#define        intotcpcb(ip)   ((struct tcpcb *)(ip)->inp_ppcb)
+#define        sototcpcb(so)   (intotcpcb(sotoinpcb(so)))
+
+/*
+ * The smoothed round-trip time and estimated variance
+ * are stored as fixed point numbers scaled by the values below.
+ * For convenience, these scales are also used in smoothing the average
+ * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
+ * With these scales, srtt has 3 bits to the right of the binary point,
+ * and thus an "ALPHA" of 0.875.  rttvar has 2 bits to the right of the
+ * binary point, and is smoothed with an ALPHA of 0.75.
+ */
+#define        TCP_RTT_SCALE           8       /* multiplier for srtt; 3 bits frac. */
+#define        TCP_RTT_SHIFT           3       /* shift for srtt; 3 bits frac. */
+#define        TCP_RTTVAR_SCALE        4       /* multiplier for rttvar; 2 bits */
+#define        TCP_RTTVAR_SHIFT        2       /* multiplier for rttvar; 2 bits */
+
+/*
+ * The initial retransmission should happen at rtt + 4 * rttvar.
+ * Because of the way we do the smoothing, srtt and rttvar
+ * will each average +1/2 tick of bias.  When we compute
+ * the retransmit timer, we want 1/2 tick of rounding and
+ * 1 extra tick because of +-1/2 tick uncertainty in the
+ * firing of the timer.  The bias will give us exactly the
+ * 1.5 tick we need.  But, because the bias is
+ * statistical, we have to test that we don't drop below
+ * the minimum feasible timer (which is 2 ticks).
+ * This macro assumes that the value of TCP_RTTVAR_SCALE
+ * is the same as the multiplier for rttvar.
+ */
+#define        TCP_REXMTVAL(tp) \
+       (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
+
+/* XXX
+ * We want to avoid doing m_pullup on incoming packets but that
+ * means avoiding dtom on the tcp reassembly code.  That in turn means
+ * keeping an mbuf pointer in the reassembly queue (since we might
+ * have a cluster).  As a quick hack, the source & destination
+ * port numbers (which are no longer needed once we've located the
+ * tcpcb) are overlayed with an mbuf pointer.
+ */
+#define REASS_MBUF(ti) (*(struct mbuf **)&((ti)->ti_t))
+
+/*
+ * TCP statistics.
+ * Many of these should be kept per connection,
+ * but that's inconvenient at the moment.
+ */
+struct tcpstat {
+       u_long  tcps_connattempt;       /* connections initiated */
+       u_long  tcps_accepts;           /* connections accepted */
+       u_long  tcps_connects;          /* connections established */
+       u_long  tcps_drops;             /* connections dropped */
+       u_long  tcps_conndrops;         /* embryonic connections dropped */
+       u_long  tcps_closed;            /* conn. closed (includes drops) */
+       u_long  tcps_segstimed;         /* segs where we tried to get rtt */
+       u_long  tcps_rttupdated;        /* times we succeeded */
+       u_long  tcps_delack;            /* delayed acks sent */
+       u_long  tcps_timeoutdrop;       /* conn. dropped in rxmt timeout */
+       u_long  tcps_rexmttimeo;        /* retransmit timeouts */
+       u_long  tcps_persisttimeo;      /* persist timeouts */
+       u_long  tcps_keeptimeo;         /* keepalive timeouts */
+       u_long  tcps_keepprobe;         /* keepalive probes sent */
+       u_long  tcps_keepdrops;         /* connections dropped in keepalive */
+
+       u_long  tcps_sndtotal;          /* total packets sent */
+       u_long  tcps_sndpack;           /* data packets sent */
+       u_long  tcps_sndbyte;           /* data bytes sent */
+       u_long  tcps_sndrexmitpack;     /* data packets retransmitted */
+       u_long  tcps_sndrexmitbyte;     /* data bytes retransmitted */
+       u_long  tcps_sndacks;           /* ack-only packets sent */
+       u_long  tcps_sndprobe;          /* window probes sent */
+       u_long  tcps_sndurg;            /* packets sent with URG only */
+       u_long  tcps_sndwinup;          /* window update-only packets sent */
+       u_long  tcps_sndctrl;           /* control (SYN|FIN|RST) packets sent */
+
+       u_long  tcps_rcvtotal;          /* total packets received */
+       u_long  tcps_rcvpack;           /* packets received in sequence */
+       u_long  tcps_rcvbyte;           /* bytes received in sequence */
+       u_long  tcps_rcvbadsum;         /* packets received with ccksum errs */
+       u_long  tcps_rcvbadoff;         /* packets received with bad offset */
+       u_long  tcps_rcvshort;          /* packets received too short */
+       u_long  tcps_rcvduppack;        /* duplicate-only packets received */
+       u_long  tcps_rcvdupbyte;        /* duplicate-only bytes received */
+       u_long  tcps_rcvpartduppack;    /* packets with some duplicate data */
+       u_long  tcps_rcvpartdupbyte;    /* dup. bytes in part-dup. packets */
+       u_long  tcps_rcvoopack;         /* out-of-order packets received */
+       u_long  tcps_rcvoobyte;         /* out-of-order bytes received */
+       u_long  tcps_rcvpackafterwin;   /* packets with data after window */
+       u_long  tcps_rcvbyteafterwin;   /* bytes rcvd after window */
+       u_long  tcps_rcvafterclose;     /* packets rcvd after "close" */
+       u_long  tcps_rcvwinprobe;       /* rcvd window probe packets */
+       u_long  tcps_rcvdupack;         /* rcvd duplicate acks */
+       u_long  tcps_rcvacktoomuch;     /* rcvd acks for unsent data */
+       u_long  tcps_rcvackpack;        /* rcvd ack packets */
+       u_long  tcps_rcvackbyte;        /* bytes acked by rcvd acks */
+       u_long  tcps_rcvwinupd;         /* rcvd window update packets */
+};
+
+#ifdef KERNEL
+struct inpcb tcb;              /* head of queue of active tcpcb's */
+struct tcpstat tcpstat;        /* tcp statistics */
+struct tcpiphdr *tcp_template();
+struct tcpcb *tcp_close(), *tcp_drop();
+struct tcpcb *tcp_timers(), *tcp_disconnect(), *tcp_usrclosed();
+#endif
diff --git a/usr/src/sys.386bsd/netinet/tcpip.h b/usr/src/sys.386bsd/netinet/tcpip.h
new file mode 100644 (file)
index 0000000..b75a813
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcpip.h     7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Tcp+ip header, after ip options removed.
+ */
+struct tcpiphdr {
+       struct  ipovly ti_i;            /* overlaid ip structure */
+       struct  tcphdr ti_t;            /* tcp header */
+};
+#define        ti_next         ti_i.ih_next
+#define        ti_prev         ti_i.ih_prev
+#define        ti_x1           ti_i.ih_x1
+#define        ti_pr           ti_i.ih_pr
+#define        ti_len          ti_i.ih_len
+#define        ti_src          ti_i.ih_src
+#define        ti_dst          ti_i.ih_dst
+#define        ti_sport        ti_t.th_sport
+#define        ti_dport        ti_t.th_dport
+#define        ti_seq          ti_t.th_seq
+#define        ti_ack          ti_t.th_ack
+#define        ti_x2           ti_t.th_x2
+#define        ti_off          ti_t.th_off
+#define        ti_flags        ti_t.th_flags
+#define        ti_win          ti_t.th_win
+#define        ti_sum          ti_t.th_sum
+#define        ti_urp          ti_t.th_urp
diff --git a/usr/src/sys.386bsd/netinet/udp.h b/usr/src/sys.386bsd/netinet/udp.h
new file mode 100644 (file)
index 0000000..ac6e55d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)udp.h       7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Udp protocol header.
+ * Per RFC 768, September, 1981.
+ */
+struct udphdr {
+       u_short uh_sport;               /* source port */
+       u_short uh_dport;               /* destination port */
+       short   uh_ulen;                /* udp length */
+       u_short uh_sum;                 /* udp checksum */
+};
diff --git a/usr/src/sys.386bsd/netinet/udp_usrreq.c b/usr/src/sys.386bsd/netinet/udp_usrreq.c
new file mode 100644 (file)
index 0000000..778fa63
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)udp_usrreq.c        7.20 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "stat.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
+#include "in_pcb.h"
+#include "ip_var.h"
+#include "ip_icmp.h"
+#include "udp.h"
+#include "udp_var.h"
+
+struct inpcb *udp_last_inpcb = &udb;
+
+/*
+ * UDP protocol implementation.
+ * Per RFC 768, August, 1980.
+ */
+udp_init()
+{
+
+       udb.inp_next = udb.inp_prev = &udb;
+}
+
+#ifndef        COMPAT_42
+int    udpcksum = 1;
+#else
+int    udpcksum = 0;           /* XXX */
+#endif
+int    udp_ttl = UDP_TTL;
+
+struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
+
+udp_input(m, iphlen)
+       register struct mbuf *m;
+       int iphlen;
+{
+       register struct ip *ip;
+       register struct udphdr *uh;
+       register struct inpcb *inp;
+       struct mbuf *opts = 0;
+       int len;
+       struct ip save_ip;
+
+       udpstat.udps_ipackets++;
+
+       /*
+        * Strip IP options, if any; should skip this,
+        * make available to user, and use on returned packets,
+        * but we don't yet have a way to check the checksum
+        * with options still present.
+        */
+       if (iphlen > sizeof (struct ip)) {
+               ip_stripoptions(m, (struct mbuf *)0);
+               iphlen = sizeof(struct ip);
+       }
+
+       /*
+        * Get IP and UDP header together in first mbuf.
+        */
+       ip = mtod(m, struct ip *);
+       if (m->m_len < iphlen + sizeof(struct udphdr)) {
+               if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
+                       udpstat.udps_hdrops++;
+                       return;
+               }
+               ip = mtod(m, struct ip *);
+       }
+       uh = (struct udphdr *)((caddr_t)ip + iphlen);
+
+       /*
+        * Make mbuf data length reflect UDP length.
+        * If not enough data to reflect UDP length, drop.
+        */
+       len = ntohs((u_short)uh->uh_ulen);
+       if (ip->ip_len != len) {
+               if (len > ip->ip_len) {
+                       udpstat.udps_badlen++;
+                       goto bad;
+               }
+               m_adj(m, len - ip->ip_len);
+               /* ip->ip_len = len; */
+       }
+       /*
+        * Save a copy of the IP header in case we want restore it
+        * for sending an ICMP error message in response.
+        */
+       save_ip = *ip;
+
+       /*
+        * Checksum extended UDP header and data.
+        */
+       if (udpcksum && uh->uh_sum) {
+               ((struct ipovly *)ip)->ih_next = 0;
+               ((struct ipovly *)ip)->ih_prev = 0;
+               ((struct ipovly *)ip)->ih_x1 = 0;
+               ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
+               if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
+                       udpstat.udps_badsum++;
+                       m_freem(m);
+                       return;
+               }
+       }
+
+       /*
+        * Locate pcb for datagram.
+        */
+       inp = udp_last_inpcb;
+       if (inp->inp_lport != uh->uh_dport ||
+           inp->inp_fport != uh->uh_sport ||
+           inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
+           inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
+               inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
+                   ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
+               if (inp)
+                       udp_last_inpcb = inp;
+               udpstat.udpps_pcbcachemiss++;
+       }
+       if (inp == 0) {
+               /* don't send ICMP response for broadcast packet */
+               udpstat.udps_noport++;
+               if (m->m_flags & M_BCAST) {
+                       udpstat.udps_noportbcast++;
+                       goto bad;
+               }
+               *ip = save_ip;
+               ip->ip_len += iphlen;
+               icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
+               return;
+       }
+
+       /*
+        * Construct sockaddr format source address.
+        * Stuff source address and datagram in user buffer.
+        */
+       udp_in.sin_port = uh->uh_sport;
+       udp_in.sin_addr = ip->ip_src;
+       if (inp->inp_flags & INP_CONTROLOPTS) {
+               struct mbuf **mp = &opts;
+               struct mbuf *udp_saveopt();
+
+               if (inp->inp_flags & INP_RECVDSTADDR) {
+                       *mp = udp_saveopt((caddr_t) &ip->ip_dst,
+                           sizeof(struct in_addr), IP_RECVDSTADDR);
+                       if (*mp)
+                               mp = &(*mp)->m_next;
+               }
+#ifdef notyet
+               /* options were tossed above */
+               if (inp->inp_flags & INP_RECVOPTS) {
+                       *mp = udp_saveopt((caddr_t) opts_deleted_above,
+                           sizeof(struct in_addr), IP_RECVOPTS);
+                       if (*mp)
+                               mp = &(*mp)->m_next;
+               }
+               /* ip_srcroute doesn't do what we want here, need to fix */
+               if (inp->inp_flags & INP_RECVRETOPTS) {
+                       *mp = udp_saveopt((caddr_t) ip_srcroute(),
+                           sizeof(struct in_addr), IP_RECVRETOPTS);
+                       if (*mp)
+                               mp = &(*mp)->m_next;
+               }
+#endif
+       }
+       iphlen += sizeof(struct udphdr);
+       m->m_len -= iphlen;
+       m->m_pkthdr.len -= iphlen;
+       m->m_data += iphlen;
+       if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
+           m, opts) == 0) {
+               udpstat.udps_fullsock++;
+               goto bad;
+       }
+       sorwakeup(inp->inp_socket);
+       return;
+bad:
+       m_freem(m);
+       if (opts)
+               m_freem(opts);
+}
+
+/*
+ * Create a "control" mbuf containing the specified data
+ * with the specified type for presentation with a datagram.
+ */
+struct mbuf *
+udp_saveopt(p, size, type)
+       caddr_t p;
+       register int size;
+       int type;
+{
+       register struct cmsghdr *cp;
+       struct mbuf *m;
+
+       if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
+               return ((struct mbuf *) NULL);
+       cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
+       bcopy(p, (caddr_t)(cp + 1), size);
+       size += sizeof(*cp);
+       m->m_len = size;
+       cp->cmsg_len = size;
+       cp->cmsg_level = IPPROTO_IP;
+       cp->cmsg_type = type;
+       return (m);
+}
+
+/*
+ * Notify a udp user of an asynchronous error;
+ * just wake up so that he can collect error status.
+ */
+udp_notify(inp, errno)
+       register struct inpcb *inp;
+{
+
+       inp->inp_socket->so_error = errno;
+       sorwakeup(inp->inp_socket);
+       sowwakeup(inp->inp_socket);
+}
+
+udp_ctlinput(cmd, sa, ip)
+       int cmd;
+       struct sockaddr *sa;
+       register struct ip *ip;
+{
+       register struct udphdr *uh;
+       extern struct in_addr zeroin_addr;
+       extern u_char inetctlerrmap[];
+
+       if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
+               return;
+       if (ip) {
+               uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+               in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
+                       cmd, udp_notify);
+       } else
+               in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
+}
+
+udp_output(inp, m, addr, control)
+       register struct inpcb *inp;
+       register struct mbuf *m;
+       struct mbuf *addr, *control;
+{
+       register struct udpiphdr *ui;
+       register int len = m->m_pkthdr.len;
+       struct in_addr laddr;
+       int s, error = 0;
+
+       if (control)
+               m_freem(control);               /* XXX */
+
+       if (addr) {
+               laddr = inp->inp_laddr;
+               if (inp->inp_faddr.s_addr != INADDR_ANY) {
+                       error = EISCONN;
+                       goto release;
+               }
+               /*
+                * Must block input while temporarily connected.
+                */
+               s = splnet();
+               error = in_pcbconnect(inp, addr);
+               if (error) {
+                       splx(s);
+                       goto release;
+               }
+       } else {
+               if (inp->inp_faddr.s_addr == INADDR_ANY) {
+                       error = ENOTCONN;
+                       goto release;
+               }
+       }
+       /*
+        * Calculate data length and get a mbuf
+        * for UDP and IP headers.
+        */
+       M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
+
+       /*
+        * Fill in mbuf with extended UDP header
+        * and addresses and length put into network format.
+        */
+       ui = mtod(m, struct udpiphdr *);
+       ui->ui_next = ui->ui_prev = 0;
+       ui->ui_x1 = 0;
+       ui->ui_pr = IPPROTO_UDP;
+       ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
+       ui->ui_src = inp->inp_laddr;
+       ui->ui_dst = inp->inp_faddr;
+       ui->ui_sport = inp->inp_lport;
+       ui->ui_dport = inp->inp_fport;
+       ui->ui_ulen = ui->ui_len;
+
+       /*
+        * Stuff checksum and output datagram.
+        */
+       ui->ui_sum = 0;
+       if (udpcksum) {
+           if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
+               ui->ui_sum = 0xffff;
+       }
+       ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
+       ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
+       ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
+       udpstat.udps_opackets++;
+       error = ip_output(m, inp->inp_options, &inp->inp_route,
+           inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
+
+       if (addr) {
+               in_pcbdisconnect(inp);
+               inp->inp_laddr = laddr;
+               splx(s);
+       }
+       return (error);
+
+release:
+       m_freem(m);
+       return (error);
+}
+
+u_long udp_sendspace = 9216;           /* really max datagram size */
+u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
+                                       /* 40 1K datagrams */
+
+/*ARGSUSED*/
+udp_usrreq(so, req, m, addr, control)
+       struct socket *so;
+       int req;
+       struct mbuf *m, *addr, *control;
+{
+       struct inpcb *inp = sotoinpcb(so);
+       int error = 0;
+       int s;
+
+       if (req == PRU_CONTROL)
+               return (in_control(so, (int)m, (caddr_t)addr,
+                       (struct ifnet *)control));
+       if (inp == NULL && req != PRU_ATTACH) {
+               error = EINVAL;
+               goto release;
+       }
+       /*
+        * Note: need to block udp_input while changing
+        * the udp pcb queue and/or pcb addresses.
+        */
+       switch (req) {
+
+       case PRU_ATTACH:
+               if (inp != NULL) {
+                       error = EINVAL;
+                       break;
+               }
+               s = splnet();
+               error = in_pcballoc(so, &udb);
+               splx(s);
+               if (error)
+                       break;
+               error = soreserve(so, udp_sendspace, udp_recvspace);
+               if (error)
+                       break;
+               ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl;
+               break;
+
+       case PRU_DETACH:
+               udp_detach(inp);
+               break;
+
+       case PRU_BIND:
+               s = splnet();
+               error = in_pcbbind(inp, addr);
+               splx(s);
+               break;
+
+       case PRU_LISTEN:
+               error = EOPNOTSUPP;
+               break;
+
+       case PRU_CONNECT:
+               if (inp->inp_faddr.s_addr != INADDR_ANY) {
+                       error = EISCONN;
+                       break;
+               }
+               s = splnet();
+               error = in_pcbconnect(inp, addr);
+               splx(s);
+               if (error == 0)
+                       soisconnected(so);
+               break;
+
+       case PRU_CONNECT2:
+               error = EOPNOTSUPP;
+               break;
+
+       case PRU_ACCEPT:
+               error = EOPNOTSUPP;
+               break;
+
+       case PRU_DISCONNECT:
+               if (inp->inp_faddr.s_addr == INADDR_ANY) {
+                       error = ENOTCONN;
+                       break;
+               }
+               s = splnet();
+               in_pcbdisconnect(inp);
+               inp->inp_laddr.s_addr = INADDR_ANY;
+               splx(s);
+               so->so_state &= ~SS_ISCONNECTED;                /* XXX */
+               break;
+
+       case PRU_SHUTDOWN:
+               socantsendmore(so);
+               break;
+
+       case PRU_SEND:
+               return (udp_output(inp, m, addr, control));
+
+       case PRU_ABORT:
+               soisdisconnected(so);
+               udp_detach(inp);
+               break;
+
+       case PRU_SOCKADDR:
+               in_setsockaddr(inp, addr);
+               break;
+
+       case PRU_PEERADDR:
+               in_setpeeraddr(inp, addr);
+               break;
+
+       case PRU_SENSE:
+               /*
+                * stat: don't bother with a blocksize.
+                */
+               return (0);
+
+       case PRU_SENDOOB:
+       case PRU_FASTTIMO:
+       case PRU_SLOWTIMO:
+       case PRU_PROTORCV:
+       case PRU_PROTOSEND:
+               error =  EOPNOTSUPP;
+               break;
+
+       case PRU_RCVD:
+       case PRU_RCVOOB:
+               return (EOPNOTSUPP);    /* do not free mbuf's */
+
+       default:
+               panic("udp_usrreq");
+       }
+
+release:
+       if (control) {
+               printf("udp control data unexpectedly retained\n");
+               m_freem(control);
+       }
+       if (m)
+               m_freem(m);
+       return (error);
+}
+
+udp_detach(inp)
+       struct inpcb *inp;
+{
+       int s = splnet();
+
+       if (inp == udp_last_inpcb)
+               udp_last_inpcb = &udb;
+       in_pcbdetach(inp);
+       splx(s);
+}
diff --git a/usr/src/sys.386bsd/netinet/udp_var.h b/usr/src/sys.386bsd/netinet/udp_var.h
new file mode 100644 (file)
index 0000000..f9e19f8
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)udp_var.h   7.7 (Berkeley) 6/28/90
+ */
+
+/*
+ * UDP kernel structures and variables.
+ */
+struct udpiphdr {
+       struct  ipovly ui_i;            /* overlaid ip structure */
+       struct  udphdr ui_u;            /* udp header */
+};
+#define        ui_next         ui_i.ih_next
+#define        ui_prev         ui_i.ih_prev
+#define        ui_x1           ui_i.ih_x1
+#define        ui_pr           ui_i.ih_pr
+#define        ui_len          ui_i.ih_len
+#define        ui_src          ui_i.ih_src
+#define        ui_dst          ui_i.ih_dst
+#define        ui_sport        ui_u.uh_sport
+#define        ui_dport        ui_u.uh_dport
+#define        ui_ulen         ui_u.uh_ulen
+#define        ui_sum          ui_u.uh_sum
+
+struct udpstat {
+                               /* input statistics: */
+       int     udps_ipackets;          /* total input packets */
+       int     udps_hdrops;            /* packet shorter than header */
+       int     udps_badsum;            /* checksum error */
+       int     udps_badlen;            /* data length larger than packet */
+       int     udps_noport;            /* no socket on port */
+       int     udps_noportbcast;       /* of above, arrived as broadcast */
+       int     udps_fullsock;          /* not delivered, input socket full */
+       int     udpps_pcbcachemiss;     /* input packets missing pcb cache */
+                               /* output statistics: */
+       int     udps_opackets;          /* total output packets */
+};
+
+#define        UDP_TTL         30      /* default time to live for UDP packets */
+
+#ifdef KERNEL
+struct inpcb udb;
+struct udpstat udpstat;
+#endif
diff --git a/usr/src/sys.386bsd/nfs/nfs.h b/usr/src/sys.386bsd/nfs/nfs.h
new file mode 100644 (file)
index 0000000..2be9d4b
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs.h       7.11 (Berkeley) 4/19/91
+ */
+
+/*
+ * Tunable constants for nfs
+ */
+
+#define        NFS_MAXIOVEC    34
+#define NFS_HZ         10              /* Ticks per second for NFS timeouts */
+#define        NFS_TIMEO       (1*NFS_HZ)      /* Default timeout = 1 second */
+#define        NFS_MINTIMEO    (NFS_HZ)        /* Min timeout to use */
+#define        NFS_MAXTIMEO    (60*NFS_HZ)     /* Max timeout to backoff to */
+#define        NFS_MINIDEMTIMEO (2*NFS_HZ)     /* Min timeout for non-idempotent ops*/
+#define        NFS_RELIABLETIMEO (5*NFS_HZ)    /* Min timeout on reliable sockets */
+#define        NFS_MAXREXMIT   100             /* Stop counting after this many */
+#define        NFS_MAXWINDOW   1024            /* Max number of outstanding requests */
+#define        NFS_RETRANS     10              /* Num of retrans for soft mounts */
+#define NFS_FISHY      8               /* Host not responding at this count */
+#define        NFS_ATTRTIMEO   5               /* Attribute cache timeout in sec */
+#define        NFS_WSIZE       8192            /* Def. write data size <= 8192 */
+#define        NFS_RSIZE       8192            /* Def. read data size <= 8192 */
+#define        NFS_MAXREADDIR  NFS_MAXDATA     /* Max. size of directory read */
+#define        NFS_MAXASYNCDAEMON 20           /* Max. number async_daemons runable */
+#define        NFS_DIRBLKSIZ   1024            /* Size of an NFS directory block */
+#define        NMOD(a)         ((a) % nfs_asyncdaemons)
+
+/*
+ * The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts.
+ * What should be in this set is open to debate, but I believe that since
+ * I/O system calls on ufs are never interrupted by signals the set should
+ * be minimal. My reasoning is that many current programs that use signals
+ * such as SIGALRM will not expect file I/O system calls to be interrupted
+ * by them and break.
+ */
+#define        NFSINT_SIGMASK  (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \
+                        sigmask(SIGHUP)|sigmask(SIGQUIT))
+
+/*
+ * Socket errors ignored for connectionless sockets??
+ * For now, ignore them all
+ */
+#define        NFSIGNORE_SOERROR(s, e) \
+               ((e) != EINTR && (e) != ERESTART && (e) != EWOULDBLOCK && \
+               ((s) & PR_CONNREQUIRED) == 0)
+
+/*
+ * Nfs outstanding request list element
+ */
+struct nfsreq {
+       struct nfsreq   *r_next;
+       struct nfsreq   *r_prev;
+       struct mbuf     *r_mreq;
+       struct mbuf     *r_mrep;
+       struct nfsmount *r_nmp;
+       struct vnode    *r_vp;
+       u_long          r_xid;
+       short           r_flags;        /* flags on request, see below */
+       short           r_retry;        /* max retransmission count */
+       short           r_rexmit;       /* current retrans count */
+       short           r_timer;        /* tick counter on reply */
+       short           r_timerinit;    /* reinit tick counter on reply */
+       struct proc     *r_procp;       /* Proc that did I/O system call */
+};
+
+/* Flag values for r_flags */
+#define R_TIMING       0x01            /* timing request (in mntp) */
+#define R_SENT         0x02            /* request has been sent */
+#define        R_SOFTTERM      0x04            /* soft mnt, too many retries */
+#define        R_INTR          0x08            /* intr mnt, signal pending */
+#define        R_SOCKERR       0x10            /* Fatal error on socket */
+#define        R_TPRINTFMSG    0x20            /* Did a tprintf msg. */
+#define        R_MUSTRESEND    0x40            /* Must resend request */
+
+#ifdef KERNEL
+/*
+ * Silly rename structure that hangs off the nfsnode until the name
+ * can be removed by nfs_inactive()
+ */
+struct sillyrename {
+       nfsv2fh_t s_fh;
+       struct  ucred *s_cred;
+       struct  vnode *s_dvp;
+       u_short s_namlen;
+       char    s_name[20];
+};
+
+/* And its flag values */
+#define REMOVE         0
+#define        RMDIR           1
+#endif /* KERNEL */
+
+/*
+ * Stats structure
+ */
+struct nfsstats {
+       int     attrcache_hits;
+       int     attrcache_misses;
+       int     lookupcache_hits;
+       int     lookupcache_misses;
+       int     direofcache_hits;
+       int     direofcache_misses;
+       int     biocache_reads;
+       int     read_bios;
+       int     read_physios;
+       int     biocache_writes;
+       int     write_bios;
+       int     write_physios;
+       int     biocache_readlinks;
+       int     readlink_bios;
+       int     biocache_readdirs;
+       int     readdir_bios;
+       int     rpccnt[NFS_NPROCS];
+       int     rpcretries;
+       int     srvrpccnt[NFS_NPROCS];
+       int     srvrpc_errs;
+       int     srv_errs;
+       int     rpcrequests;
+       int     rpctimeouts;
+       int     rpcunexpected;
+       int     rpcinvalid;
+       int     srvcache_inproghits;
+       int     srvcache_idemdonehits;
+       int     srvcache_nonidemdonehits;
+       int     srvcache_misses;
+};
+
+#ifdef KERNEL
+struct nfsstats nfsstats;
+#endif /* KERNEL */
diff --git a/usr/src/sys.386bsd/nfs/nfs_bio.c b/usr/src/sys.386bsd/nfs/nfs_bio.c
new file mode 100644 (file)
index 0000000..44a48a1
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs_bio.c   7.19 (Berkeley) 4/16/91
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "buf.h"
+#include "uio.h"
+#include "namei.h"
+#include "vnode.h"
+#include "trace.h"
+#include "mount.h"
+#include "resourcevar.h"
+
+#include "nfsnode.h"
+#include "nfsv2.h"
+#include "nfs.h"
+#include "nfsiom.h"
+#include "nfsmount.h"
+
+/* True and false, how exciting */
+#define        TRUE    1
+#define        FALSE   0
+
+/*
+ * Vnode op for read using bio
+ * Any similarity to readip() is purely coincidental
+ */
+nfs_bioread(vp, uio, ioflag, cred)
+       register struct vnode *vp;
+       register struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+       register struct nfsnode *np = VTONFS(vp);
+       register int biosize;
+       struct buf *bp;
+       struct vattr vattr;
+       daddr_t lbn, bn, rablock;
+       int diff, error = 0;
+       long n, on;
+
+#ifdef lint
+       ioflag = ioflag;
+#endif /* lint */
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_READ)
+               panic("nfs_read mode");
+#endif
+       if (uio->uio_resid == 0)
+               return (0);
+       if (uio->uio_offset < 0 && vp->v_type != VDIR)
+               return (EINVAL);
+       biosize = VFSTONFS(vp->v_mount)->nm_rsize;
+       /*
+        * If the file's modify time on the server has changed since the
+        * last read rpc or you have written to the file,
+        * you may have lost data cache consistency with the
+        * server, so flush all of the file's data out of the cache.
+        * Then force a getattr rpc to ensure that you have up to date
+        * attributes.
+        * NB: This implies that cache data can be read when up to
+        * NFS_ATTRTIMEO seconds out of date. If you find that you need current
+        * attributes this could be forced by setting n_attrstamp to 0 before
+        * the nfs_dogetattr() call.
+        */
+       if (vp->v_type != VLNK) {
+               if (np->n_flag & NMODIFIED) {
+                       np->n_flag &= ~NMODIFIED;
+                       vinvalbuf(vp, TRUE);
+                       np->n_attrstamp = 0;
+                       np->n_direofoffset = 0;
+                       if (error = nfs_dogetattr(vp, &vattr, cred, 1,
+                           uio->uio_procp))
+                               return (error);
+                       np->n_mtime = vattr.va_mtime.tv_sec;
+               } else {
+                       if (error = nfs_dogetattr(vp, &vattr, cred, 1,
+                           uio->uio_procp))
+                               return (error);
+                       if (np->n_mtime != vattr.va_mtime.tv_sec) {
+                               np->n_direofoffset = 0;
+                               vinvalbuf(vp, TRUE);
+                               np->n_mtime = vattr.va_mtime.tv_sec;
+                       }
+               }
+       }
+       do {
+           switch (vp->v_type) {
+           case VREG:
+               nfsstats.biocache_reads++;
+               lbn = uio->uio_offset / biosize;
+               on = uio->uio_offset & (biosize-1);
+               n = MIN((unsigned)(biosize - on), uio->uio_resid);
+               diff = np->n_size - uio->uio_offset;
+               if (diff <= 0)
+                       return (error);
+               if (diff < n)
+                       n = diff;
+               bn = lbn*(biosize/DEV_BSIZE);
+               rablock = (lbn+1)*(biosize/DEV_BSIZE);
+               if (vp->v_lastr + 1 == lbn &&
+                   np->n_size > (rablock * DEV_BSIZE))
+                       error = breada(vp, bn, biosize, rablock, biosize,
+                               cred, &bp);
+               else
+                       error = bread(vp, bn, biosize, cred, &bp);
+               vp->v_lastr = lbn;
+               if (bp->b_resid) {
+                  diff = (on >= (biosize-bp->b_resid)) ? 0 :
+                       (biosize-bp->b_resid-on);
+                  n = MIN(n, diff);
+               }
+               break;
+           case VLNK:
+               nfsstats.biocache_readlinks++;
+               on = 0;
+               error = bread(vp, (daddr_t)0, NFS_MAXPATHLEN, cred, &bp);
+               n = MIN(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
+               break;
+           case VDIR:
+               nfsstats.biocache_readdirs++;
+               on = 0;
+               error = bread(vp, uio->uio_offset, NFS_DIRBLKSIZ, cred, &bp);
+               n = MIN(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
+               break;
+           };
+           if (error) {
+               brelse(bp);
+               return (error);
+           }
+           if (n > 0)
+               error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
+           switch (vp->v_type) {
+           case VREG:
+               if (n+on == biosize || uio->uio_offset == np->n_size)
+                       bp->b_flags |= B_AGE;
+               break;
+           case VLNK:
+               n = 0;
+               break;
+           case VDIR:
+               uio->uio_offset = bp->b_blkno;
+               break;
+           };
+           brelse(bp);
+       } while (error == 0 && uio->uio_resid > 0 && n != 0);
+       return (error);
+}
+
+/*
+ * Vnode op for write using bio
+ */
+nfs_write(vp, uio, ioflag, cred)
+       register struct vnode *vp;
+       register struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+       struct proc *p = uio->uio_procp;
+       register int biosize;
+       struct buf *bp;
+       struct nfsnode *np = VTONFS(vp);
+       struct vattr vattr;
+       daddr_t lbn, bn;
+       int n, on, error = 0;
+
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_WRITE)
+               panic("nfs_write mode");
+       if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
+               panic("nfs_write proc");
+#endif
+       if (vp->v_type != VREG)
+               return (EIO);
+       /* Should we try and do this ?? */
+       if (ioflag & (IO_APPEND | IO_SYNC)) {
+               if (np->n_flag & NMODIFIED) {
+                       np->n_flag &= ~NMODIFIED;
+                       vinvalbuf(vp, TRUE);
+               }
+               if (ioflag & IO_APPEND) {
+                       np->n_attrstamp = 0;
+                       if (error = nfs_dogetattr(vp, &vattr, cred, 1, p))
+                               return (error);
+                       uio->uio_offset = np->n_size;
+               }
+               return (nfs_writerpc(vp, uio, cred));
+       }
+#ifdef notdef
+       cnt = uio->uio_resid;
+       osize = np->n_size;
+#endif
+       if (uio->uio_offset < 0)
+               return (EINVAL);
+       if (uio->uio_resid == 0)
+               return (0);
+       /*
+        * Maybe this should be above the vnode op call, but so long as
+        * file servers have no limits, i don't think it matters
+        */
+       if (uio->uio_offset + uio->uio_resid >
+             p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+               psignal(p, SIGXFSZ);
+               return (EFBIG);
+       }
+       /*
+        * I use nm_rsize, not nm_wsize so that all buffer cache blocks
+        * will be the same size within a filesystem. nfs_writerpc will
+        * still use nm_wsize when sizing the rpc's.
+        */
+       biosize = VFSTONFS(vp->v_mount)->nm_rsize;
+       np->n_flag |= NMODIFIED;
+       do {
+               nfsstats.biocache_writes++;
+               lbn = uio->uio_offset / biosize;
+               on = uio->uio_offset & (biosize-1);
+               n = MIN((unsigned)(biosize - on), uio->uio_resid);
+               if (uio->uio_offset+n > np->n_size) {
+                       np->n_size = uio->uio_offset+n;
+                       vnode_pager_setsize(vp, np->n_size);
+               }
+               bn = lbn*(biosize/DEV_BSIZE);
+again:
+               bp = getblk(vp, bn, biosize);
+               if (bp->b_wcred == NOCRED) {
+                       crhold(cred);
+                       bp->b_wcred = cred;
+               }
+               if (bp->b_dirtyend > 0) {
+                       /*
+                        * If the new write will leave a contiguous dirty
+                        * area, just update the b_dirtyoff and b_dirtyend,
+                        * otherwise force a write rpc of the old dirty area.
+                        */
+                       if (on <= bp->b_dirtyend && (on+n) >= bp->b_dirtyoff) {
+                               bp->b_dirtyoff = MIN(on, bp->b_dirtyoff);
+                               bp->b_dirtyend = MAX((on+n), bp->b_dirtyend);
+                       } else {
+                               bp->b_proc = p;
+                               if (error = bwrite(bp))
+                                       return (error);
+                               goto again;
+                       }
+               } else {
+                       bp->b_dirtyoff = on;
+                       bp->b_dirtyend = on+n;
+               }
+               if (error = uiomove(bp->b_un.b_addr + on, n, uio)) {
+                       brelse(bp);
+                       return (error);
+               }
+               if ((n+on) == biosize) {
+                       bp->b_flags |= B_AGE;
+                       bp->b_proc = (struct proc *)0;
+                       bawrite(bp);
+               } else {
+                       bp->b_proc = (struct proc *)0;
+                       bdwrite(bp);
+               }
+       } while (error == 0 && uio->uio_resid > 0 && n != 0);
+#ifdef notdef
+       /* Should we try and do this for nfs ?? */
+       if (error && (ioflag & IO_UNIT)) {
+               np->n_size = osize;
+               uio->uio_offset -= cnt - uio->uio_resid;
+               uio->uio_resid = cnt;
+       }
+#endif
+       return (error);
+}
diff --git a/usr/src/sys.386bsd/nfs/nfs_node.c b/usr/src/sys.386bsd/nfs/nfs_node.c
new file mode 100644 (file)
index 0000000..810378e
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs_node.c  7.34 (Berkeley) 5/15/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "mount.h"
+#include "namei.h"
+#include "vnode.h"
+#include "kernel.h"
+#include "malloc.h"
+
+#include "nfsv2.h"
+#include "nfs.h"
+#include "nfsnode.h"
+#include "nfsmount.h"
+
+/* The request list head */
+extern struct nfsreq nfsreqh;
+
+#define        NFSNOHSZ        512
+#if    ((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
+#define        NFSNOHASH(fhsum)        ((fhsum)&(NFSNOHSZ-1))
+#else
+#define        NFSNOHASH(fhsum)        (((unsigned)(fhsum))%NFSNOHSZ)
+#endif
+
+union nhead {
+       union  nhead *nh_head[2];
+       struct nfsnode *nh_chain[2];
+} nhead[NFSNOHSZ];
+
+#define TRUE   1
+#define        FALSE   0
+
+/*
+ * Initialize hash links for nfsnodes
+ * and build nfsnode free list.
+ */
+nfs_nhinit()
+{
+       register int i;
+       register union  nhead *nh = nhead;
+
+#ifndef lint
+       if (VN_MAXPRIVATE < sizeof(struct nfsnode))
+               panic("nfs_nhinit: too small");
+#endif /* not lint */
+       for (i = NFSNOHSZ; --i >= 0; nh++) {
+               nh->nh_head[0] = nh;
+               nh->nh_head[1] = nh;
+       }
+}
+
+/*
+ * Compute an entry in the NFS hash table structure
+ */
+union nhead *
+nfs_hash(fhp)
+       register nfsv2fh_t *fhp;
+{
+       register u_char *fhpp;
+       register u_long fhsum;
+       int i;
+
+       fhpp = &fhp->fh_bytes[0];
+       fhsum = 0;
+       for (i = 0; i < NFSX_FH; i++)
+               fhsum += *fhpp++;
+       return (&nhead[NFSNOHASH(fhsum)]);
+}
+
+/*
+ * Look up a vnode/nfsnode by file handle.
+ * Callers must check for mount points!!
+ * In all cases, a pointer to a
+ * nfsnode structure is returned.
+ */
+nfs_nget(mntp, fhp, npp)
+       struct mount *mntp;
+       register nfsv2fh_t *fhp;
+       struct nfsnode **npp;
+{
+       register struct nfsnode *np;
+       register struct vnode *vp;
+       extern struct vnodeops nfsv2_vnodeops;
+       struct vnode *nvp;
+       union nhead *nh;
+       int error;
+
+       nh = nfs_hash(fhp);
+loop:
+       for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) {
+               if (mntp != NFSTOV(np)->v_mount ||
+                   bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
+                       continue;
+               if ((np->n_flag & NLOCKED) != 0) {
+                       np->n_flag |= NWANT;
+                       (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0);
+                       goto loop;
+               }
+               vp = NFSTOV(np);
+               if (vget(vp))
+                       goto loop;
+               *npp = np;
+               return(0);
+       }
+       if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) {
+               *npp = 0;
+               return (error);
+       }
+       vp = nvp;
+       np = VTONFS(vp);
+       np->n_vnode = vp;
+       /*
+        * Insert the nfsnode in the hash queue for its new file handle
+        */
+       np->n_flag = 0;
+       insque(np, nh);
+       nfs_lock(vp);
+       bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
+       np->n_attrstamp = 0;
+       np->n_direofoffset = 0;
+       np->n_sillyrename = (struct sillyrename *)0;
+       np->n_size = 0;
+       np->n_mtime = 0;
+       *npp = np;
+       return (0);
+}
+
+nfs_inactive(vp, p)
+       struct vnode *vp;
+       struct proc *p;
+{
+       register struct nfsnode *np;
+       register struct sillyrename *sp;
+       struct nfsnode *dnp;
+       extern int prtactive;
+
+       np = VTONFS(vp);
+       if (prtactive && vp->v_usecount != 0)
+               vprint("nfs_inactive: pushing active", vp);
+       nfs_lock(vp);
+       sp = np->n_sillyrename;
+       np->n_sillyrename = (struct sillyrename *)0;
+       if (sp) {
+               /*
+                * Remove the silly file that was rename'd earlier
+                */
+               if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
+                       sp->s_dvp = NFSTOV(dnp);
+                       nfs_removeit(sp, p);
+                       nfs_nput(sp->s_dvp);
+               }
+               crfree(sp->s_cred);
+               vrele(sp->s_dvp);
+               free((caddr_t)sp, M_NFSREQ);
+       }
+       nfs_unlock(vp);
+       np->n_flag &= NMODIFIED;
+#ifdef notdef
+       /*
+        * Scan the request list for any requests left hanging about
+        */
+       s = splnet();
+       rep = nfsreqh.r_next;
+       while (rep && rep != &nfsreqh) {
+               if (rep->r_vp == vp) {
+                       rep->r_prev->r_next = rep2 = rep->r_next;
+                       rep->r_next->r_prev = rep->r_prev;
+                       m_freem(rep->r_mreq);
+                       if (rep->r_mrep != NULL)
+                               m_freem(rep->r_mrep);
+                       free((caddr_t)rep, M_NFSREQ);
+                       rep = rep2;
+               } else
+                       rep = rep->r_next;
+       }
+       splx(s);
+#endif
+       return (0);
+}
+
+/*
+ * Reclaim an nfsnode so that it can be used for other purposes.
+ */
+nfs_reclaim(vp)
+       register struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+       extern int prtactive;
+
+       if (prtactive && vp->v_usecount != 0)
+               vprint("nfs_reclaim: pushing active", vp);
+       /*
+        * Remove the nfsnode from its hash chain.
+        */
+       remque(np);
+       np->n_forw = np;
+       np->n_back = np;
+       cache_purge(vp);
+       np->n_flag = 0;
+       np->n_direofoffset = 0;
+       return (0);
+}
+
+/*
+ * In theory, NFS does not need locking, but we make provision
+ * for doing it just in case it is needed.
+ */
+int donfslocking = 0;
+/*
+ * Lock an nfsnode
+ */
+
+nfs_lock(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+
+       if (!donfslocking)
+               return;
+       while (np->n_flag & NLOCKED) {
+               np->n_flag |= NWANT;
+               if (np->n_lockholder == curproc->p_pid)
+                       panic("locking against myself");
+               np->n_lockwaiter = curproc->p_pid;
+               (void) tsleep((caddr_t)np, PINOD, "nfslock", 0);
+       }
+       np->n_lockwaiter = 0;
+       np->n_lockholder = curproc->p_pid;
+       np->n_flag |= NLOCKED;
+}
+
+/*
+ * Unlock an nfsnode
+ */
+nfs_unlock(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+
+       np->n_lockholder = 0;
+       np->n_flag &= ~NLOCKED;
+       if (np->n_flag & NWANT) {
+               np->n_flag &= ~NWANT;
+               wakeup((caddr_t)np);
+       }
+}
+
+/*
+ * Check for a locked nfsnode
+ */
+nfs_islocked(vp)
+       struct vnode *vp;
+{
+
+       if (VTONFS(vp)->n_flag & NLOCKED)
+               return (1);
+       return (0);
+}
+
+/*
+ * Unlock and vrele()
+ * since I can't decide if dirs. should be locked, I will check for
+ * the lock and be flexible
+ */
+nfs_nput(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+
+       if (np->n_flag & NLOCKED)
+               nfs_unlock(vp);
+       vrele(vp);
+}
+
+/*
+ * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Currently nothing to do.
+ */
+/* ARGSUSED */
+nfs_abortop(ndp)
+       struct nameidata *ndp;
+{
+
+       if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
+               FREE(ndp->ni_pnbuf, M_NAMEI);
+       return (0);
+}
diff --git a/usr/src/sys.386bsd/nfs/nfs_serv.c b/usr/src/sys.386bsd/nfs/nfs_serv.c
new file mode 100644 (file)
index 0000000..a83dfe9
--- /dev/null
@@ -0,0 +1,1495 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs_serv.c  7.40 (Berkeley) 5/15/91
+ */
+
+/*
+ * nfs version 2 server calls to vnode ops
+ * - these routines generally have 3 phases
+ *   1 - break down and validate rpc request in mbuf list
+ *   2 - do the vnode ops for the request
+ *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
+ *   3 - build the rpc reply in an mbuf list
+ *   nb:
+ *     - do not mix the phases, since the nfsm_?? macros can return failures
+ *       on a bad rpc or similar and do not do any vrele() or vput()'s
+ *
+ *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
+ *     error number iff error != 0 whereas
+ *     returning an error from the server function implies a fatal error
+ *     such as a badly constructed rpc request that should be dropped without
+ *     a reply.
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "file.h"
+#include "namei.h"
+#include "vnode.h"
+#include "mount.h"
+#include "mbuf.h"
+
+#include "../ufs/quota.h"
+#include "../ufs/inode.h"
+#include "../ufs/dir.h"
+
+#include "nfsv2.h"
+#include "nfs.h"
+#include "xdr_subs.h"
+#include "nfsm_subs.h"
+
+/* Defs */
+#define        TRUE    1
+#define        FALSE   0
+
+/* Global vars */
+extern u_long nfs_procids[NFS_NPROCS];
+extern u_long nfs_xdrneg1;
+extern u_long nfs_false, nfs_true;
+nfstype nfs_type[9]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
+                     NFCHR, NFNON };
+
+/*
+ * nfs getattr service
+ */
+nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register struct nfsv2_fattr *fp;
+       struct vattr va;
+       register struct vattr *vap = &va;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+               nfsm_reply(0);
+       error = VOP_GETATTR(vp, vap, cred, p);
+       vput(vp);
+       nfsm_reply(NFSX_FATTR);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_srvfillattr;
+       nfsm_srvdone;
+}
+
+/*
+ * nfs setattr service
+ */
+nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       struct vattr va;
+       register struct vattr *vap = &va;
+       register struct nfsv2_sattr *sp;
+       register struct nfsv2_fattr *fp;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+               nfsm_reply(0);
+       if (error = nfsrv_access(vp, VWRITE, cred, p))
+               goto out;
+       VATTR_NULL(vap);
+       /*
+        * Nah nah nah nah na nah
+        * There is a bug in the Sun client that puts 0xffff in the mode
+        * field of sattr when it should put in 0xffffffff. The u_short
+        * doesn't sign extend.
+        * --> check the low order 2 bytes for 0xffff
+        */
+       if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
+               vap->va_mode = nfstov_mode(sp->sa_mode);
+       if (sp->sa_uid != nfs_xdrneg1)
+               vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
+       if (sp->sa_gid != nfs_xdrneg1)
+               vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
+       if (sp->sa_size != nfs_xdrneg1)
+               vap->va_size = fxdr_unsigned(u_long, sp->sa_size);
+       /*
+        * The usec field of sa_atime is overloaded with the va_flags field
+        * for 4.4BSD clients. Hopefully other clients always set both the
+        * sec and usec fields to -1 when not setting the atime.
+        */
+       if (sp->sa_atime.tv_sec != nfs_xdrneg1) {
+               vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec);
+               vap->va_atime.tv_usec = 0;
+       }
+       if (sp->sa_atime.tv_usec != nfs_xdrneg1)
+               vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec);
+       if (sp->sa_mtime.tv_sec != nfs_xdrneg1)
+               fxdr_time(&sp->sa_mtime, &vap->va_mtime);
+       if (error = VOP_SETATTR(vp, vap, cred, p)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       error = VOP_GETATTR(vp, vap, cred, p);
+out:
+       vput(vp);
+       nfsm_reply(NFSX_FATTR);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_srvfillattr;
+       nfsm_srvdone;
+}
+
+/*
+ * nfs lookup rpc
+ */
+nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register struct nfsv2_fattr *fp;
+       struct nameidata nd;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       register caddr_t cp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       long len;
+       struct vattr va, *vap = &va;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       nd.ni_cred = cred;
+       nd.ni_nameiop = LOOKUP | LOCKLEAF;
+       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+               nfsm_reply(0);
+       vp = nd.ni_vp;
+       bzero((caddr_t)fhp, sizeof(nfh));
+       fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+       if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       error = VOP_GETATTR(vp, vap, cred, p);
+       vput(vp);
+       nfsm_reply(NFSX_FH+NFSX_FATTR);
+       nfsm_srvfhtom(fhp);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_srvfillattr;
+       nfsm_srvdone;
+}
+
+/*
+ * nfs readlink service
+ */
+nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
+       register struct iovec *ivp = iv;
+       register struct mbuf *mp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       struct uio io, *uiop = &io;
+       int i, tlen, len;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       len = 0;
+       i = 0;
+       while (len < NFS_MAXPATHLEN) {
+               MGET(mp, M_WAIT, MT_DATA);
+               MCLGET(mp, M_WAIT);
+               mp->m_len = NFSMSIZ(mp);
+               if (len == 0)
+                       mp3 = mp2 = mp;
+               else {
+                       mp2->m_next = mp;
+                       mp2 = mp;
+               }
+               if ((len+mp->m_len) > NFS_MAXPATHLEN) {
+                       mp->m_len = NFS_MAXPATHLEN-len;
+                       len = NFS_MAXPATHLEN;
+               } else
+                       len += mp->m_len;
+               ivp->iov_base = mtod(mp, caddr_t);
+               ivp->iov_len = mp->m_len;
+               i++;
+               ivp++;
+       }
+       uiop->uio_iov = iv;
+       uiop->uio_iovcnt = i;
+       uiop->uio_offset = 0;
+       uiop->uio_resid = len;
+       uiop->uio_rw = UIO_READ;
+       uiop->uio_segflg = UIO_SYSSPACE;
+       uiop->uio_procp = (struct proc *)0;
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) {
+               m_freem(mp3);
+               nfsm_reply(0);
+       }
+       if (vp->v_type != VLNK) {
+               error = EINVAL;
+               goto out;
+       }
+       error = VOP_READLINK(vp, uiop, cred);
+out:
+       vput(vp);
+       if (error)
+               m_freem(mp3);
+       nfsm_reply(NFSX_UNSIGNED);
+       if (uiop->uio_resid > 0) {
+               len -= uiop->uio_resid;
+               tlen = nfsm_rndup(len);
+               nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
+       }
+       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+       *tl = txdr_unsigned(len);
+       mb->m_next = mp3;
+       nfsm_srvdone;
+}
+
+/*
+ * nfs read service
+ */
+nfsrv_read(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register struct iovec *iv;
+       struct iovec *iv2;
+       register struct mbuf *m;
+       register struct nfsv2_fattr *fp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       struct mbuf *m2, *m3;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       struct uio io, *uiop = &io;
+       struct vattr va, *vap = &va;
+       int i, cnt, len, left, siz, tlen;
+       off_t off;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+       off = fxdr_unsigned(off_t, *tl);
+       nfsm_srvstrsiz(cnt, NFS_MAXDATA);
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+               nfsm_reply(0);
+       if (error = nfsrv_access(vp, VREAD | VEXEC, cred, p)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       len = left = cnt;
+       /*
+        * Generate the mbuf list with the uio_iov ref. to it.
+        */
+       i = 0;
+       m3 = (struct mbuf *)0;
+#ifdef lint
+       m2 = (struct mbuf *)0;
+#endif /* lint */
+       MALLOC(iv, struct iovec *,
+              ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), M_TEMP,
+              M_WAITOK);
+       iv2 = iv;
+       while (left > 0) {
+               MGET(m, M_WAIT, MT_DATA);
+               if (left > MINCLSIZE)
+                       MCLGET(m, M_WAIT);
+               m->m_len = 0;
+               siz = min(M_TRAILINGSPACE(m), left);
+               m->m_len = siz;
+               iv->iov_base = mtod(m, caddr_t);
+               iv->iov_len = siz;
+               iv++;
+               i++;
+               left -= siz;
+               if (m3) {
+                       m2->m_next = m;
+                       m2 = m;
+               } else
+                       m3 = m2 = m;
+       }
+       uiop->uio_iov = iv2;
+       uiop->uio_iovcnt = i;
+       uiop->uio_offset = off;
+       uiop->uio_resid = cnt;
+       uiop->uio_rw = UIO_READ;
+       uiop->uio_segflg = UIO_SYSSPACE;
+       uiop->uio_procp = (struct proc *)0;
+       error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
+       off = uiop->uio_offset;
+       FREE((caddr_t)iv2, M_TEMP);
+       if (error) {
+               m_freem(m3);
+               vput(vp);
+               nfsm_reply(0);
+       }
+       if (error = VOP_GETATTR(vp, vap, cred, p))
+               m_freem(m3);
+       vput(vp);
+       nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_srvfillattr;
+       len -= uiop->uio_resid;
+       if (len > 0) {
+               tlen = nfsm_rndup(len);
+               if (cnt != tlen || tlen != len)
+                       nfsm_adj(m3, cnt-tlen, tlen-len);
+       } else {
+               m_freem(m3);
+               m3 = (struct mbuf *)0;
+       }
+       nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+       *tl = txdr_unsigned(len);
+       mb->m_next = m3;
+       nfsm_srvdone;
+}
+
+/*
+ * nfs write service
+ */
+nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register struct iovec *ivp;
+       register struct mbuf *mp;
+       register struct nfsv2_fattr *fp;
+       struct iovec iv[NFS_MAXIOVEC];
+       struct vattr va;
+       register struct vattr *vap = &va;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       struct uio io, *uiop = &io;
+       off_t off;
+       long siz, len, xfer;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_disect(tl, u_long *, 4*NFSX_UNSIGNED);
+       off = fxdr_unsigned(off_t, *++tl);
+       tl += 2;
+       len = fxdr_unsigned(long, *tl);
+       if (len > NFS_MAXDATA || len <= 0) {
+               error = EBADRPC;
+               nfsm_reply(0);
+       }
+       if (dpos == (mtod(md, caddr_t)+md->m_len)) {
+               mp = md->m_next;
+               if (mp == NULL) {
+                       error = EBADRPC;
+                       nfsm_reply(0);
+               }
+       } else {
+               mp = md;
+               siz = dpos-mtod(mp, caddr_t);
+               mp->m_len -= siz;
+               NFSMADV(mp, siz);
+       }
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+               nfsm_reply(0);
+       if (error = nfsrv_access(vp, VWRITE, cred, p)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       uiop->uio_resid = 0;
+       uiop->uio_rw = UIO_WRITE;
+       uiop->uio_segflg = UIO_SYSSPACE;
+       uiop->uio_procp = (struct proc *)0;
+       /*
+        * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
+        * loop until done.
+        */
+       while (len > 0 && uiop->uio_resid == 0) {
+               ivp = iv;
+               siz = 0;
+               uiop->uio_iov = ivp;
+               uiop->uio_iovcnt = 0;
+               uiop->uio_offset = off;
+               while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) {
+                       ivp->iov_base = mtod(mp, caddr_t);
+                       if (len < mp->m_len)
+                               ivp->iov_len = xfer = len;
+                       else
+                               ivp->iov_len = xfer = mp->m_len;
+#ifdef notdef
+                       /* Not Yet .. */
+                       if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
+                               ivp->iov_op = NULL;     /* what should it be ?? */
+                       else
+                               ivp->iov_op = NULL;
+#endif
+                       uiop->uio_iovcnt++;
+                       ivp++;
+                       len -= xfer;
+                       siz += xfer;
+                       mp = mp->m_next;
+               }
+               if (len > 0 && mp == NULL) {
+                       error = EBADRPC;
+                       vput(vp);
+                       nfsm_reply(0);
+               }
+               uiop->uio_resid = siz;
+               if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED,
+                       cred)) {
+                       vput(vp);
+                       nfsm_reply(0);
+               }
+               off = uiop->uio_offset;
+       }
+       error = VOP_GETATTR(vp, vap, cred, p);
+       vput(vp);
+       nfsm_reply(NFSX_FATTR);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_srvfillattr;
+       nfsm_srvdone;
+}
+
+/*
+ * nfs create service
+ * now does a truncate to 0 length via. setattr if it already exists
+ */
+nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register struct nfsv2_fattr *fp;
+       struct vattr va;
+       register struct vattr *vap = &va;
+       struct nameidata nd;
+       register caddr_t cp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       long rdev;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       long len;
+
+       nd.ni_nameiop = 0;
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       nd.ni_cred = cred;
+       nd.ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF | SAVESTART;
+       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+               nfsm_reply(0);
+       VATTR_NULL(vap);
+       nfsm_disect(tl, u_long *, NFSX_SATTR);
+       /*
+        * Iff doesn't exist, create it
+        * otherwise just truncate to 0 length
+        *   should I set the mode too ??
+        */
+       if (nd.ni_vp == NULL) {
+               vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl));
+               if (vap->va_type == VNON)
+                       vap->va_type = VREG;
+               vap->va_mode = nfstov_mode(*tl);
+               rdev = fxdr_unsigned(long, *(tl+3));
+               if (vap->va_type == VREG || vap->va_type == VSOCK) {
+                       vrele(nd.ni_startdir);
+                       if (error = VOP_CREATE(&nd, vap, p))
+                               nfsm_reply(0);
+                       FREE(nd.ni_pnbuf, M_NAMEI);
+               } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
+                       vap->va_type == VFIFO) {
+                       if (vap->va_type == VCHR && rdev == 0xffffffff)
+                               vap->va_type = VFIFO;
+                       if (vap->va_type == VFIFO) {
+#ifndef FIFO
+                               VOP_ABORTOP(&nd);
+                               vput(nd.ni_dvp);
+                               error = ENXIO;
+                               goto out;
+#endif /* FIFO */
+                       } else if (error = suser(cred, (short *)0)) {
+                               VOP_ABORTOP(&nd);
+                               vput(nd.ni_dvp);
+                               goto out;
+                       } else
+                               vap->va_rdev = (dev_t)rdev;
+                       if (error = VOP_MKNOD(&nd, vap, cred, p)) {
+                               vrele(nd.ni_startdir);
+                               nfsm_reply(0);
+                       }
+                       nd.ni_nameiop &= ~(OPMASK | LOCKPARENT | SAVESTART);
+                       nd.ni_nameiop |= LOOKUP;
+                       if (error = lookup(&nd, p)) {
+                               free(nd.ni_pnbuf, M_NAMEI);
+                               nfsm_reply(0);
+                       }
+                       FREE(nd.ni_pnbuf, M_NAMEI);
+                       if (nd.ni_more) {
+                               vrele(nd.ni_dvp);
+                               vput(nd.ni_vp);
+                               VOP_ABORTOP(&nd);
+                               error = EINVAL;
+                               nfsm_reply(0);
+                       }
+               } else {
+                       VOP_ABORTOP(&nd);
+                       vput(nd.ni_dvp);
+                       error = ENXIO;
+                       goto out;
+               }
+               vp = nd.ni_vp;
+       } else {
+               vrele(nd.ni_startdir);
+               free(nd.ni_pnbuf, M_NAMEI);
+               vp = nd.ni_vp;
+               if (nd.ni_dvp == vp)
+                       vrele(nd.ni_dvp);
+               else
+                       vput(nd.ni_dvp);
+               VOP_ABORTOP(&nd);
+               vap->va_size = 0;
+               if (error = VOP_SETATTR(vp, vap, cred, p)) {
+                       vput(vp);
+                       nfsm_reply(0);
+               }
+       }
+       bzero((caddr_t)fhp, sizeof(nfh));
+       fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+       if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       error = VOP_GETATTR(vp, vap, cred, p);
+       vput(vp);
+       nfsm_reply(NFSX_FH+NFSX_FATTR);
+       nfsm_srvfhtom(fhp);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_srvfillattr;
+       return (error);
+nfsmout:
+       if (nd.ni_nameiop)
+               vrele(nd.ni_startdir);
+       VOP_ABORTOP(&nd);
+       if (nd.ni_dvp == nd.ni_vp)
+               vrele(nd.ni_dvp);
+       else
+               vput(nd.ni_dvp);
+       if (nd.ni_vp)
+               vput(nd.ni_vp);
+       return (error);
+
+out:
+       vrele(nd.ni_startdir);
+       free(nd.ni_pnbuf, M_NAMEI);
+       nfsm_reply(0);
+}
+
+/*
+ * nfs remove service
+ */
+nfsrv_remove(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       struct nameidata nd;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mreq;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       long len;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       nd.ni_cred = cred;
+       nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+               nfsm_reply(0);
+       vp = nd.ni_vp;
+       if (vp->v_type == VDIR &&
+               (error = suser(cred, (short *)0)))
+               goto out;
+       /*
+        * The root of a mounted filesystem cannot be deleted.
+        */
+       if (vp->v_flag & VROOT) {
+               error = EBUSY;
+               goto out;
+       }
+       if (vp->v_flag & VTEXT)
+               (void) vnode_pager_uncache(vp);
+out:
+       if (!error) {
+               error = VOP_REMOVE(&nd, p);
+       } else {
+               VOP_ABORTOP(&nd);
+               if (nd.ni_dvp == vp)
+                       vrele(nd.ni_dvp);
+               else
+                       vput(nd.ni_dvp);
+               vput(vp);
+       }
+       nfsm_reply(0);
+       nfsm_srvdone;
+}
+
+/*
+ * nfs rename service
+ */
+nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mreq;
+       struct nameidata fromnd, tond;
+       struct vnode *fvp, *tvp, *tdvp;
+       nfsv2fh_t fnfh, tnfh;
+       fhandle_t *ffhp, *tfhp;
+       long len, len2;
+       int rootflg = 0;
+
+       ffhp = &fnfh.fh_generic;
+       tfhp = &tnfh.fh_generic;
+       fromnd.ni_nameiop = 0;
+       tond.ni_nameiop = 0;
+       nfsm_srvmtofh(ffhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       /*
+        * Remember if we are root so that we can reset cr_uid before
+        * the second nfs_namei() call
+        */
+       if (cred->cr_uid == 0)
+               rootflg++;
+       fromnd.ni_cred = cred;
+       fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART;
+       if (error = nfs_namei(&fromnd, ffhp, len, &md, &dpos, p))
+               nfsm_reply(0);
+       fvp = fromnd.ni_vp;
+       nfsm_srvmtofh(tfhp);
+       nfsm_strsiz(len2, NFS_MAXNAMLEN);
+       if (rootflg)
+               cred->cr_uid = 0;
+       tond.ni_cred = cred;
+       tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE
+               | SAVESTART;
+       if (error = nfs_namei(&tond, tfhp, len2, &md, &dpos, p)) {
+               VOP_ABORTOP(&fromnd);
+               vrele(fromnd.ni_dvp);
+               vrele(fvp);
+               goto out1;
+       }
+       tdvp = tond.ni_dvp;
+       tvp = tond.ni_vp;
+       if (tvp != NULL) {
+               if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
+                       error = EISDIR;
+                       goto out;
+               } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
+                       error = ENOTDIR;
+                       goto out;
+               }
+       }
+       if (fvp->v_mount != tdvp->v_mount) {
+               error = EXDEV;
+               goto out;
+       }
+       if (fvp == tdvp)
+               error = EINVAL;
+       /*
+        * If source is the same as the destination (that is the
+        * same vnode with the same name in the same directory),
+        * then there is nothing to do.
+        */
+       if (fvp == tvp && fromnd.ni_dvp == tdvp &&
+           fromnd.ni_namelen == tond.ni_namelen &&
+           !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen))
+               error = -1;
+out:
+       if (!error) {
+               error = VOP_RENAME(&fromnd, &tond, p);
+       } else {
+               VOP_ABORTOP(&tond);
+               if (tdvp == tvp)
+                       vrele(tdvp);
+               else
+                       vput(tdvp);
+               if (tvp)
+                       vput(tvp);
+               VOP_ABORTOP(&fromnd);
+               vrele(fromnd.ni_dvp);
+               vrele(fvp);
+       }
+       vrele(tond.ni_startdir);
+       FREE(tond.ni_pnbuf, M_NAMEI);
+out1:
+       vrele(fromnd.ni_startdir);
+       FREE(fromnd.ni_pnbuf, M_NAMEI);
+       nfsm_reply(0);
+       return (error);
+
+nfsmout:
+       if (tond.ni_nameiop) {
+               vrele(tond.ni_startdir);
+               FREE(tond.ni_pnbuf, M_NAMEI);
+       }
+       if (fromnd.ni_nameiop) {
+               vrele(fromnd.ni_startdir);
+               FREE(fromnd.ni_pnbuf, M_NAMEI);
+               VOP_ABORTOP(&fromnd);
+               vrele(fromnd.ni_dvp);
+               vrele(fvp);
+       }
+       return (error);
+}
+
+/*
+ * nfs link service
+ */
+nfsrv_link(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       struct nameidata nd;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mreq;
+       struct vnode *vp, *xp;
+       nfsv2fh_t nfh, dnfh;
+       fhandle_t *fhp, *dfhp;
+       long len;
+
+       fhp = &nfh.fh_generic;
+       dfhp = &dnfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_srvmtofh(dfhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred))
+               nfsm_reply(0);
+       if (vp->v_type == VDIR && (error = suser(cred, NULL)))
+               goto out1;
+       nd.ni_cred = cred;
+       nd.ni_nameiop = CREATE | LOCKPARENT;
+       if (error = nfs_namei(&nd, dfhp, len, &md, &dpos, p))
+               goto out1;
+       xp = nd.ni_vp;
+       if (xp != NULL) {
+               error = EEXIST;
+               goto out;
+       }
+       xp = nd.ni_dvp;
+       if (vp->v_mount != xp->v_mount)
+               error = EXDEV;
+out:
+       if (!error) {
+               error = VOP_LINK(vp, &nd, p);
+       } else {
+               VOP_ABORTOP(&nd);
+               if (nd.ni_dvp == nd.ni_vp)
+                       vrele(nd.ni_dvp);
+               else
+                       vput(nd.ni_dvp);
+               if (nd.ni_vp)
+                       vrele(nd.ni_vp);
+       }
+out1:
+       vrele(vp);
+       nfsm_reply(0);
+       nfsm_srvdone;
+}
+
+/*
+ * nfs symbolic link service
+ */
+nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       struct vattr va;
+       struct nameidata nd;
+       register struct vattr *vap = &va;
+       register u_long *tl;
+       register long t1;
+       struct nfsv2_sattr *sp;
+       caddr_t bpos;
+       struct uio io;
+       struct iovec iv;
+       int error = 0;
+       char *pathcp, *cp2;
+       struct mbuf *mb, *mreq;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       long len, len2;
+
+       pathcp = (char *)0;
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       nd.ni_cred = cred;
+       nd.ni_nameiop = CREATE | LOCKPARENT;
+       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+               goto out;
+       nfsm_strsiz(len2, NFS_MAXPATHLEN);
+       MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
+       iv.iov_base = pathcp;
+       iv.iov_len = len2;
+       io.uio_resid = len2;
+       io.uio_offset = 0;
+       io.uio_iov = &iv;
+       io.uio_iovcnt = 1;
+       io.uio_segflg = UIO_SYSSPACE;
+       io.uio_rw = UIO_READ;
+       io.uio_procp = (struct proc *)0;
+       nfsm_mtouio(&io, len2);
+       nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
+       *(pathcp + len2) = '\0';
+       if (nd.ni_vp) {
+               VOP_ABORTOP(&nd);
+               if (nd.ni_dvp == nd.ni_vp)
+                       vrele(nd.ni_dvp);
+               else
+                       vput(nd.ni_dvp);
+               vrele(nd.ni_vp);
+               error = EEXIST;
+               goto out;
+       }
+       VATTR_NULL(vap);
+       vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
+       error = VOP_SYMLINK(&nd, vap, pathcp, p);
+out:
+       if (pathcp)
+               FREE(pathcp, M_TEMP);
+       nfsm_reply(0);
+       return (error);
+nfsmout:
+       VOP_ABORTOP(&nd);
+       if (nd.ni_dvp == nd.ni_vp)
+               vrele(nd.ni_dvp);
+       else
+               vput(nd.ni_dvp);
+       if (nd.ni_vp)
+               vrele(nd.ni_vp);
+       if (pathcp)
+               FREE(pathcp, M_TEMP);
+       return (error);
+}
+
+/*
+ * nfs mkdir service
+ */
+nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       struct vattr va;
+       register struct vattr *vap = &va;
+       register struct nfsv2_fattr *fp;
+       struct nameidata nd;
+       register caddr_t cp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       long len;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       nd.ni_cred = cred;
+       nd.ni_nameiop = CREATE | LOCKPARENT;
+       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+               nfsm_reply(0);
+       nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+       VATTR_NULL(vap);
+       vap->va_type = VDIR;
+       vap->va_mode = nfstov_mode(*tl++);
+       vp = nd.ni_vp;
+       if (vp != NULL) {
+               VOP_ABORTOP(&nd);
+               if (nd.ni_dvp == vp)
+                       vrele(nd.ni_dvp);
+               else
+                       vput(nd.ni_dvp);
+               vrele(vp);
+               error = EEXIST;
+               nfsm_reply(0);
+       }
+       if (error = VOP_MKDIR(&nd, vap, p))
+               nfsm_reply(0);
+       vp = nd.ni_vp;
+       bzero((caddr_t)fhp, sizeof(nfh));
+       fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+       if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       error = VOP_GETATTR(vp, vap, cred, p);
+       vput(vp);
+       nfsm_reply(NFSX_FH+NFSX_FATTR);
+       nfsm_srvfhtom(fhp);
+       nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
+       nfsm_srvfillattr;
+       return (error);
+nfsmout:
+       VOP_ABORTOP(&nd);
+       if (nd.ni_dvp == nd.ni_vp)
+               vrele(nd.ni_dvp);
+       else
+               vput(nd.ni_dvp);
+       if (nd.ni_vp)
+               vrele(nd.ni_vp);
+       return (error);
+}
+
+/*
+ * nfs rmdir service
+ */
+nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf *mrep, *md, **mrq;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mreq;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       long len;
+       struct nameidata nd;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+       nd.ni_cred = cred;
+       nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+       if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p))
+               nfsm_reply(0);
+       vp = nd.ni_vp;
+       if (vp->v_type != VDIR) {
+               error = ENOTDIR;
+               goto out;
+       }
+       /*
+        * No rmdir "." please.
+        */
+       if (nd.ni_dvp == vp) {
+               error = EINVAL;
+               goto out;
+       }
+       /*
+        * The root of a mounted filesystem cannot be deleted.
+        */
+       if (vp->v_flag & VROOT)
+               error = EBUSY;
+out:
+       if (!error) {
+               error = VOP_RMDIR(&nd, p);
+       } else {
+               VOP_ABORTOP(&nd);
+               if (nd.ni_dvp == nd.ni_vp)
+                       vrele(nd.ni_dvp);
+               else
+                       vput(nd.ni_dvp);
+               vput(vp);
+       }
+       nfsm_reply(0);
+       nfsm_srvdone;
+}
+
+/*
+ * nfs readdir service
+ * - mallocs what it thinks is enough to read
+ *     count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
+ * - calls VOP_READDIR()
+ * - loops around building the reply
+ *     if the output generated exceeds count break out of loop
+ *     The nfsm_clget macro is used here so that the reply will be packed
+ *     tightly in mbuf clusters.
+ * - it only knows that it has encountered eof when the VOP_READDIR()
+ *     reads nothing
+ * - as such one readdir rpc will return eof false although you are there
+ *     and then the next will return eof
+ * - it trims out records with d_ino == 0
+ *     this doesn't matter for Unix clients, but they might confuse clients
+ *     for other os'.
+ * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
+ *     than requested, but this may not apply to all filesystems. For
+ *     example, client NFS does not { although it is never remote mounted
+ *     anyhow }
+ * PS: The NFS protocol spec. does not clarify what the "count" byte
+ *     argument is a count of.. just name strings and file id's or the
+ *     entire reply rpc or ...
+ *     I tried just file name and id sizes and it confused the Sun client,
+ *     so I am using the full rpc size now. The "paranoia.." comment refers
+ *     to including the status longwords that are not a part of the dir.
+ *     "entry" structures, but are in the rpc.
+ */
+nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register char *bp, *be;
+       register struct mbuf *mp;
+       register struct direct *dp;
+       register caddr_t cp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       char *cpos, *cend;
+       int len, nlen, rem, xfer, tsiz, i;
+       struct vnode *vp;
+       struct mbuf *mp2, *mp3;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       struct uio io;
+       struct iovec iv;
+       int siz, cnt, fullsiz, eofflag;
+       u_long on;
+       char *rbuf;
+       off_t off, toff;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       nfsm_disect(tl, u_long *, 2*NFSX_UNSIGNED);
+       toff = fxdr_unsigned(off_t, *tl++);
+       off = (toff & ~(NFS_DIRBLKSIZ-1));
+       on = (toff & (NFS_DIRBLKSIZ-1));
+       cnt = fxdr_unsigned(int, *tl);
+       siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
+       if (cnt > NFS_MAXREADDIR)
+               siz = NFS_MAXREADDIR;
+       fullsiz = siz;
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+               nfsm_reply(0);
+       if (error = nfsrv_access(vp, VEXEC, cred, p)) {
+               vput(vp);
+               nfsm_reply(0);
+       }
+       VOP_UNLOCK(vp);
+       MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
+again:
+       iv.iov_base = rbuf;
+       iv.iov_len = fullsiz;
+       io.uio_iov = &iv;
+       io.uio_iovcnt = 1;
+       io.uio_offset = off;
+       io.uio_resid = fullsiz;
+       io.uio_segflg = UIO_SYSSPACE;
+       io.uio_rw = UIO_READ;
+       io.uio_procp = (struct proc *)0;
+       error = VOP_READDIR(vp, &io, cred, &eofflag);
+       off = io.uio_offset;
+       if (error) {
+               vrele(vp);
+               free((caddr_t)rbuf, M_TEMP);
+               nfsm_reply(0);
+       }
+       if (io.uio_resid) {
+               siz -= io.uio_resid;
+
+               /*
+                * If nothing read, return eof
+                * rpc reply
+                */
+               if (siz == 0) {
+                       vrele(vp);
+                       nfsm_reply(2*NFSX_UNSIGNED);
+                       nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+                       *tl++ = nfs_false;
+                       *tl = nfs_true;
+                       FREE((caddr_t)rbuf, M_TEMP);
+                       return (0);
+               }
+       }
+
+       /*
+        * Check for degenerate cases of nothing useful read.
+        * If so go try again
+        */
+       cpos = rbuf + on;
+       cend = rbuf + siz;
+       dp = (struct direct *)cpos;
+       while (cpos < cend && dp->d_ino == 0) {
+               cpos += dp->d_reclen;
+               dp = (struct direct *)cpos;
+       }
+       if (cpos >= cend) {
+               toff = off;
+               siz = fullsiz;
+               on = 0;
+               goto again;
+       }
+
+       cpos = rbuf + on;
+       cend = rbuf + siz;
+       dp = (struct direct *)cpos;
+       vrele(vp);
+       len = 3*NFSX_UNSIGNED;  /* paranoia, probably can be 0 */
+       bp = be = (caddr_t)0;
+       mp3 = (struct mbuf *)0;
+       nfsm_reply(siz);
+
+       /* Loop through the records and build reply */
+       while (cpos < cend) {
+               if (dp->d_ino != 0) {
+                       nlen = dp->d_namlen;
+                       rem = nfsm_rndup(nlen)-nlen;
+       
+                       /*
+                        * As noted above, the NFS spec. is not clear about what
+                        * should be included in "count" as totalled up here in
+                        * "len".
+                        */
+                       len += (4*NFSX_UNSIGNED+nlen+rem);
+                       if (len > cnt) {
+                               eofflag = 0;
+                               break;
+                       }
+       
+                       /* Build the directory record xdr from the direct entry */
+                       nfsm_clget;
+                       *tl = nfs_true;
+                       bp += NFSX_UNSIGNED;
+                       nfsm_clget;
+                       *tl = txdr_unsigned(dp->d_ino);
+                       bp += NFSX_UNSIGNED;
+                       nfsm_clget;
+                       *tl = txdr_unsigned(nlen);
+                       bp += NFSX_UNSIGNED;
+       
+                       /* And loop arround copying the name */
+                       xfer = nlen;
+                       cp = dp->d_name;
+                       while (xfer > 0) {
+                               nfsm_clget;
+                               if ((bp+xfer) > be)
+                                       tsiz = be-bp;
+                               else
+                                       tsiz = xfer;
+                               bcopy(cp, bp, tsiz);
+                               bp += tsiz;
+                               xfer -= tsiz;
+                               if (xfer > 0)
+                                       cp += tsiz;
+                       }
+                       /* And null pad to a long boundary */
+                       for (i = 0; i < rem; i++)
+                               *bp++ = '\0';
+                       nfsm_clget;
+       
+                       /* Finish off the record */
+                       toff += dp->d_reclen;
+                       *tl = txdr_unsigned(toff);
+                       bp += NFSX_UNSIGNED;
+               } else
+                       toff += dp->d_reclen;
+               cpos += dp->d_reclen;
+               dp = (struct direct *)cpos;
+       }
+       nfsm_clget;
+       *tl = nfs_false;
+       bp += NFSX_UNSIGNED;
+       nfsm_clget;
+       if (eofflag)
+               *tl = nfs_true;
+       else
+               *tl = nfs_false;
+       bp += NFSX_UNSIGNED;
+       if (bp < be)
+               mp->m_len = bp-mtod(mp, caddr_t);
+       mb->m_next = mp3;
+       FREE(rbuf, M_TEMP);
+       nfsm_srvdone;
+}
+
+/*
+ * nfs statfs service
+ */
+nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       register struct statfs *sf;
+       register struct nfsv2_statfs *sfp;
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       int error = 0;
+       char *cp2;
+       struct mbuf *mb, *mb2, *mreq;
+       struct vnode *vp;
+       nfsv2fh_t nfh;
+       fhandle_t *fhp;
+       struct statfs statfs;
+
+       fhp = &nfh.fh_generic;
+       nfsm_srvmtofh(fhp);
+       if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
+               nfsm_reply(0);
+       sf = &statfs;
+       error = VFS_STATFS(vp->v_mount, sf, p);
+       vput(vp);
+       nfsm_reply(NFSX_STATFS);
+       nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
+       sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
+       sfp->sf_bsize = txdr_unsigned(sf->f_fsize);
+       sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
+       sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
+       sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
+       nfsm_srvdone;
+}
+
+/*
+ * Null operation, used by clients to ping server
+ */
+/* ARGSUSED */
+nfsrv_null(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       caddr_t bpos;
+       int error = 0;
+       struct mbuf *mb, *mreq;
+
+       error = VNOVAL;
+       nfsm_reply(0);
+       return (error);
+}
+
+/*
+ * No operation, used for obsolete procedures
+ */
+/* ARGSUSED */
+nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat, p)
+       struct mbuf **mrq;
+       struct mbuf *mrep, *md;
+       caddr_t dpos;
+       struct ucred *cred;
+       u_long xid;
+       int *repstat;
+       struct proc *p;
+{
+       caddr_t bpos;
+       int error = 0;
+       struct mbuf *mb, *mreq;
+
+       error = EPROCUNAVAIL;
+       nfsm_reply(0);
+       return (error);
+}
+
+/*
+ * Perform access checking for vnodes obtained from file handles that would
+ * refer to files already opened by a Unix client. You cannot just use
+ * vn_writechk() and VOP_ACCESS() for two reasons.
+ * 1 - You must check for MNT_EXRDONLY as well as MNT_RDONLY for the write case
+ * 2 - The owner is to be given access irrespective of mode bits so that
+ *     processes that chmod after opening a file don't break. I don't like
+ *     this because it opens a security hole, but since the nfs server opens
+ *     a security hole the size of a barn door anyhow, what the heck.
+ */
+nfsrv_access(vp, flags, cred, p)
+       register struct vnode *vp;
+       int flags;
+       register struct ucred *cred;
+       struct proc *p;
+{
+       struct vattr vattr;
+       int error;
+       if (flags & VWRITE) {
+               /* Just vn_writechk() changed to check MNT_EXRDONLY */
+               /*
+                * Disallow write attempts on read-only file systems;
+                * unless the file is a socket or a block or character
+                * device resident on the file system.
+                */
+               if (vp->v_mount->mnt_flag & (MNT_RDONLY | MNT_EXRDONLY)) {
+                       switch (vp->v_type) {
+                       case VREG: case VDIR: case VLNK:
+                               return (EROFS);
+                       }
+               }
+               /*
+                * If there's shared text associated with
+                * the inode, try to free it up once.  If
+                * we fail, we can't allow writing.
+                */
+               if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
+                       return (ETXTBSY);
+       }
+       if (error = VOP_GETATTR(vp, &vattr, cred, p))
+               return (error);
+       if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
+           cred->cr_uid != vattr.va_uid)
+               return (error);
+       return (0);
+}
diff --git a/usr/src/sys.386bsd/nfs/nfs_socket.c b/usr/src/sys.386bsd/nfs/nfs_socket.c
new file mode 100644 (file)
index 0000000..ff092d4
--- /dev/null
@@ -0,0 +1,1413 @@
+/*
+ * Copyright (c) 1989, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs_socket.c        7.23 (Berkeley) 4/20/91
+ */
+
+/*
+ * Socket operations for use by nfs
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "mount.h"
+#include "kernel.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "namei.h"
+#include "vnode.h"
+#include "domain.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "syslog.h"
+#include "tprintf.h"
+#include "../netinet/in.h"
+#include "../netinet/tcp.h"
+
+#include "rpcv2.h"
+#include "nfsv2.h"
+#include "nfs.h"
+#include "xdr_subs.h"
+#include "nfsm_subs.h"
+#include "nfsmount.h"
+
+#define        TRUE    1
+#define        FALSE   0
+
+/*
+ * External data, mostly RPC constants in XDR form
+ */
+extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
+       rpc_msgaccepted, rpc_call;
+extern u_long nfs_prog, nfs_vers;
+/* Maybe these should be bits in a u_long ?? */
+extern int nonidempotent[NFS_NPROCS];
+static int compressrequest[NFS_NPROCS] = {
+       FALSE,
+       TRUE,
+       TRUE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       FALSE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+};
+int    nfs_sbwait();
+void   nfs_disconnect();
+struct mbuf *nfs_compress(), *nfs_uncompress();
+
+int    nfsrv_null(),
+       nfsrv_getattr(),
+       nfsrv_setattr(),
+       nfsrv_lookup(),
+       nfsrv_readlink(),
+       nfsrv_read(),
+       nfsrv_write(),
+       nfsrv_create(),
+       nfsrv_remove(),
+       nfsrv_rename(),
+       nfsrv_link(),
+       nfsrv_symlink(),
+       nfsrv_mkdir(),
+       nfsrv_rmdir(),
+       nfsrv_readdir(),
+       nfsrv_statfs(),
+       nfsrv_noop();
+
+int (*nfsrv_procs[NFS_NPROCS])() = {
+       nfsrv_null,
+       nfsrv_getattr,
+       nfsrv_setattr,
+       nfsrv_noop,
+       nfsrv_lookup,
+       nfsrv_readlink,
+       nfsrv_read,
+       nfsrv_noop,
+       nfsrv_write,
+       nfsrv_create,
+       nfsrv_remove,
+       nfsrv_rename,
+       nfsrv_link,
+       nfsrv_symlink,
+       nfsrv_mkdir,
+       nfsrv_rmdir,
+       nfsrv_readdir,
+       nfsrv_statfs,
+};
+
+struct nfsreq nfsreqh;
+int nfsrexmtthresh = NFS_FISHY;
+int nfs_tcpnodelay = 1;
+
+/*
+ * Initialize sockets and congestion for a new NFS connection.
+ * We do not free the sockaddr if error.
+ */
+nfs_connect(nmp)
+       register struct nfsmount *nmp;
+{
+       register struct socket *so;
+       int s, error, bufsize;
+       struct mbuf *m;
+
+       nmp->nm_so = (struct socket *)0;
+       if (error = socreate(mtod(nmp->nm_nam, struct sockaddr *)->sa_family,
+               &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto))
+               goto bad;
+       so = nmp->nm_so;
+       nmp->nm_soflags = so->so_proto->pr_flags;
+
+       if (nmp->nm_sotype == SOCK_DGRAM)
+               bufsize = min(4 * (nmp->nm_wsize + NFS_MAXPKTHDR),
+                   NFS_MAXPACKET);
+       else
+               bufsize = min(4 * (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof(u_long)),
+                   NFS_MAXPACKET + sizeof(u_long));
+       if (error = soreserve(so, bufsize, bufsize))
+               goto bad;
+
+       /*
+        * Protocols that do not require connections may be optionally left
+        * unconnected for servers that reply from a port other than NFS_PORT.
+        */
+       if (nmp->nm_flag & NFSMNT_NOCONN) {
+               if (nmp->nm_soflags & PR_CONNREQUIRED) {
+                       error = ENOTCONN;
+                       goto bad;
+               }
+       } else {
+               if (error = soconnect(so, nmp->nm_nam))
+                       goto bad;
+
+               /*
+                * Wait for the connection to complete. Cribbed from the
+                * connect system call but with the wait at negative prio.
+                */
+               s = splnet();
+               while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
+                       (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "nfscon", 0);
+               splx(s);
+               if (so->so_error) {
+                       error = so->so_error;
+                       goto bad;
+               }
+       }
+       if (nmp->nm_sotype == SOCK_DGRAM) {
+               if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) {
+                       so->so_rcv.sb_timeo = (5 * hz);
+                       so->so_snd.sb_timeo = (5 * hz);
+               } else {
+                       so->so_rcv.sb_timeo = 0;
+                       so->so_snd.sb_timeo = 0;
+               }
+               nmp->nm_rto = NFS_TIMEO;
+       } else {
+               if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_SPONGY | NFSMNT_INT)) {
+                       so->so_rcv.sb_timeo = (5 * hz);
+                       so->so_snd.sb_timeo = (5 * hz);
+               } else {
+                       so->so_rcv.sb_timeo = 0;
+                       so->so_snd.sb_timeo = 0;
+               }
+               if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+                       MGET(m, M_WAIT, MT_SOOPTS);
+                       *mtod(m, int *) = 1;
+                       m->m_len = sizeof(int);
+                       sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
+               }
+               if (so->so_proto->pr_domain->dom_family == AF_INET &&
+                   so->so_proto->pr_protocol == IPPROTO_TCP &&
+                   nfs_tcpnodelay) {
+                       MGET(m, M_WAIT, MT_SOOPTS);
+                       *mtod(m, int *) = 1;
+                       m->m_len = sizeof(int);
+                       sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
+               }
+               nmp->nm_rto = 10 * NFS_TIMEO;           /* XXX */
+       }
+       so->so_rcv.sb_flags |= SB_NOINTR;
+       so->so_snd.sb_flags |= SB_NOINTR;
+
+       /* Initialize other non-zero congestion variables */
+       nmp->nm_window = 2;                     /* Initial send window */
+       nmp->nm_ssthresh = NFS_MAXWINDOW;       /* Slowstart threshold */
+       nmp->nm_rttvar = nmp->nm_rto << 1;
+       nmp->nm_sent = 0;
+       nmp->nm_currexmit = 0;
+       return (0);
+
+bad:
+       nfs_disconnect(nmp);
+       return (error);
+}
+
+/*
+ * Reconnect routine:
+ * Called when a connection is broken on a reliable protocol.
+ * - clean up the old socket
+ * - nfs_connect() again
+ * - set R_MUSTRESEND for all outstanding requests on mount point
+ * If this fails the mount point is DEAD!
+ * nb: Must be called with the nfs_solock() set on the mount point.
+ */
+nfs_reconnect(rep, nmp)
+       register struct nfsreq *rep;
+       register struct nfsmount *nmp;
+{
+       register struct nfsreq *rp;
+       int error;
+
+       nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
+           "trying reconnect");
+       while (error = nfs_connect(nmp)) {
+#ifdef lint
+               error = error;
+#endif /* lint */
+               if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp))
+                       return (EINTR);
+               (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0);
+       }
+       nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
+           "reconnected");
+
+       /*
+        * Loop through outstanding request list and fix up all requests
+        * on old socket.
+        */
+       rp = nfsreqh.r_next;
+       while (rp != &nfsreqh) {
+               if (rp->r_nmp == nmp)
+                       rp->r_flags |= R_MUSTRESEND;
+               rp = rp->r_next;
+       }
+       return (0);
+}
+
+/*
+ * NFS disconnect. Clean up and unlink.
+ */
+void
+nfs_disconnect(nmp)
+       register struct nfsmount *nmp;
+{
+       register struct socket *so;
+
+       if (nmp->nm_so) {
+               so = nmp->nm_so;
+               nmp->nm_so = (struct socket *)0;
+               soshutdown(so, 2);
+               soclose(so);
+       }
+}
+
+/*
+ * This is the nfs send routine. For connection based socket types, it
+ * must be called with an nfs_solock() on the socket.
+ * "rep == NULL" indicates that it has been called from a server.
+ */
+nfs_send(so, nam, top, rep)
+       register struct socket *so;
+       struct mbuf *nam;
+       register struct mbuf *top;
+       struct nfsreq *rep;
+{
+       struct mbuf *sendnam;
+       int error, soflags;
+
+       if (rep) {
+               if (rep->r_flags & R_SOFTTERM) {
+                       m_freem(top);
+                       return (EINTR);
+               }
+               if (rep->r_nmp->nm_so == NULL &&
+                   (error = nfs_reconnect(rep, rep->r_nmp)))
+                       return (error);
+               rep->r_flags &= ~R_MUSTRESEND;
+               so = rep->r_nmp->nm_so;
+               soflags = rep->r_nmp->nm_soflags;
+       } else
+               soflags = so->so_proto->pr_flags;
+       if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
+               sendnam = (struct mbuf *)0;
+       else
+               sendnam = nam;
+
+       error = sosend(so, sendnam, (struct uio *)0, top,
+               (struct mbuf *)0, 0);
+       if (error == EWOULDBLOCK && rep) {
+               if (rep->r_flags & R_SOFTTERM)
+                       error = EINTR;
+               else {
+                       rep->r_flags |= R_MUSTRESEND;
+                       error = 0;
+               }
+       }
+       /*
+        * Ignore socket errors??
+        */
+       if (error && error != EINTR && error != ERESTART)
+               error = 0;
+       return (error);
+}
+
+/*
+ * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
+ * done by soreceive(), but for SOCK_STREAM we must deal with the Record
+ * Mark and consolidate the data into a new mbuf list.
+ * nb: Sometimes TCP passes the data up to soreceive() in long lists of
+ *     small mbufs.
+ * For SOCK_STREAM we must be very careful to read an entire record once
+ * we have read any of it, even if the system call has been interrupted.
+ */
+nfs_receive(so, aname, mp, rep)
+       register struct socket *so;
+       struct mbuf **aname;
+       struct mbuf **mp;
+       register struct nfsreq *rep;
+{
+       struct uio auio;
+       struct iovec aio;
+       register struct mbuf *m;
+       struct mbuf *m2, *mnew, **mbp;
+       caddr_t fcp, tcp;
+       u_long len;
+       struct mbuf **getnam;
+       int error, siz, mlen, soflags, rcvflg;
+
+       /*
+        * Set up arguments for soreceive()
+        */
+       *mp = (struct mbuf *)0;
+       *aname = (struct mbuf *)0;
+       if (rep)
+               soflags = rep->r_nmp->nm_soflags;
+       else
+               soflags = so->so_proto->pr_flags;
+
+       /*
+        * For reliable protocols, lock against other senders/receivers
+        * in case a reconnect is necessary.
+        * For SOCK_STREAM, first get the Record Mark to find out how much
+        * more there is to get.
+        * We must lock the socket against other receivers
+        * until we have an entire rpc request/reply.
+        */
+       if (soflags & PR_CONNREQUIRED) {
+tryagain:
+               /*
+                * Check for fatal errors and resending request.
+                */
+               if (rep) {
+                       /*
+                        * Ugh: If a reconnect attempt just happened, nm_so
+                        * would have changed. NULL indicates a failed
+                        * attempt that has essentially shut down this
+                        * mount point.
+                        */
+                       if (rep->r_mrep || (so = rep->r_nmp->nm_so) == NULL ||
+                               (rep->r_flags & R_SOFTTERM))
+                               return (EINTR);
+                       while (rep->r_flags & R_MUSTRESEND) {
+                               m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
+                               nfsstats.rpcretries++;
+                               if (error = nfs_send(so, rep->r_nmp->nm_nam, m,
+                                       rep))
+                                       goto errout;
+                       }
+               }
+               if ((soflags & PR_ATOMIC) == 0) {
+                       aio.iov_base = (caddr_t) &len;
+                       aio.iov_len = sizeof(u_long);
+                       auio.uio_iov = &aio;
+                       auio.uio_iovcnt = 1;
+                       auio.uio_segflg = UIO_SYSSPACE;
+                       auio.uio_rw = UIO_READ;
+                       auio.uio_procp = (struct proc *)0;
+                       auio.uio_offset = 0;
+                       auio.uio_resid = sizeof(u_long);
+                       do {
+                           rcvflg = MSG_WAITALL;
+                           error = soreceive(so, (struct mbuf **)0, &auio,
+                               (struct mbuf **)0, (struct mbuf **)0, &rcvflg);
+                           if (error == EWOULDBLOCK && rep) {
+                               if (rep->r_flags & R_SOFTTERM)
+                                       return (EINTR);
+                               if (rep->r_flags & R_MUSTRESEND)
+                                       goto tryagain;
+                           }
+                       } while (error == EWOULDBLOCK);
+                       if (!error && auio.uio_resid > 0) {
+                           if (rep)
+                               log(LOG_INFO,
+                                  "short receive (%d/%d) from nfs server %s\n",
+                                  sizeof(u_long) - auio.uio_resid,
+                                  sizeof(u_long),
+                                rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
+                           error = EPIPE;
+                       }
+                       if (error)
+                               goto errout;
+                       len = ntohl(len) & ~0x80000000;
+                       /*
+                        * This is SERIOUS! We are out of sync with the sender
+                        * and forcing a disconnect/reconnect is all I can do.
+                        */
+                       if (len > NFS_MAXPACKET) {
+                           if (rep)
+                               log(LOG_ERR, "%s (%d) from nfs server %s\n",
+                                   "impossible packet length",
+                                   len,
+                                rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
+                           error = EFBIG;
+                           goto errout;
+                       }
+                       auio.uio_resid = len;
+                       do {
+                           rcvflg = MSG_WAITALL;
+                           error =  soreceive(so, (struct mbuf **)0,
+                               &auio, mp, (struct mbuf **)0, &rcvflg);
+                       } while (error == EWOULDBLOCK || error == EINTR ||
+                                error == ERESTART);
+                       if (!error && auio.uio_resid > 0) {
+                           if (rep)
+                               log(LOG_INFO,
+                                  "short receive (%d/%d) from nfs server %s\n",
+                                  len - auio.uio_resid, len,
+                                rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
+                           error = EPIPE;
+                       }
+               } else {
+                       auio.uio_resid = len = 1000000; /* Anything Big */
+                       do {
+                           rcvflg = 0;
+                           error =  soreceive(so, (struct mbuf **)0,
+                               &auio, mp, (struct mbuf **)0, &rcvflg);
+                           if (error == EWOULDBLOCK && rep) {
+                               if (rep->r_flags & R_SOFTTERM)
+                                       return (EINTR);
+                               if (rep->r_flags & R_MUSTRESEND)
+                                       goto tryagain;
+                           }
+                       } while (error == EWOULDBLOCK);
+                       if (!error && *mp == NULL)
+                               error = EPIPE;
+                       len -= auio.uio_resid;
+               }
+errout:
+               if (error && rep && error != EINTR && error != ERESTART) {
+                       m_freem(*mp);
+                       *mp = (struct mbuf *)0;
+                       if (error != EPIPE && rep)
+                               log(LOG_INFO,
+                                   "receive error %d from nfs server %s\n",
+                                   error,
+                                rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
+                       nfs_disconnect(rep->r_nmp);
+                       error = nfs_reconnect(rep, rep->r_nmp);
+                       if (!error)
+                               goto tryagain;
+               }
+       } else {
+               if (so->so_state & SS_ISCONNECTED)
+                       getnam = (struct mbuf **)0;
+               else
+                       getnam = aname;
+               auio.uio_resid = len = 1000000;
+               do {
+                       rcvflg = 0;
+                       error =  soreceive(so, getnam, &auio, mp,
+                               (struct mbuf **)0, &rcvflg);
+                       if (error == EWOULDBLOCK && rep &&
+                           (rep->r_flags & R_SOFTTERM))
+                               return (EINTR);
+               } while (error == EWOULDBLOCK);
+               len -= auio.uio_resid;
+       }
+       if (error) {
+               m_freem(*mp);
+               *mp = (struct mbuf *)0;
+       }
+       /*
+        * Search for any mbufs that are not a multiple of 4 bytes long.
+        * These could cause pointer alignment problems, so copy them to
+        * well aligned mbufs.
+        */
+       m = *mp;
+       mbp = mp;
+       while (m) {
+               /*
+                * All this for something that may never happen.
+                */
+               if (m->m_next && (m->m_len & 0x3)) {
+                       printf("nfs_rcv odd length!\n");
+                       mlen = 0;
+                       while (m) {
+                               fcp = mtod(m, caddr_t);
+                               while (m->m_len > 0) {
+                                       if (mlen == 0) {
+                                               MGET(m2, M_WAIT, MT_DATA);
+                                               if (len >= MINCLSIZE)
+                                                       MCLGET(m2, M_WAIT);
+                                               m2->m_len = 0;
+                                               mlen = M_TRAILINGSPACE(m2);
+                                               tcp = mtod(m2, caddr_t);
+                                               *mbp = m2;
+                                               mbp = &m2->m_next;
+                                       }
+                                       siz = MIN(mlen, m->m_len);
+                                       bcopy(fcp, tcp, siz);
+                                       m2->m_len += siz;
+                                       mlen -= siz;
+                                       len -= siz;
+                                       tcp += siz;
+                                       m->m_len -= siz;
+                                       fcp += siz;
+                               }
+                               MFREE(m, mnew);
+                               m = mnew;
+                       }
+                       break;
+               }
+               len -= m->m_len;
+               mbp = &m->m_next;
+               m = m->m_next;
+       }
+       return (error);
+}
+
+/*
+ * Implement receipt of reply on a socket.
+ * We must search through the list of received datagrams matching them
+ * with outstanding requests using the xid, until ours is found.
+ */
+/* ARGSUSED */
+nfs_reply(nmp, myrep)
+       struct nfsmount *nmp;
+       struct nfsreq *myrep;
+{
+       register struct mbuf *m;
+       register struct nfsreq *rep;
+       register int error = 0;
+       u_long rxid;
+       struct mbuf *mp, *nam;
+       char *cp;
+       int cnt, xfer;
+
+       /*
+        * Loop around until we get our own reply
+        */
+       for (;;) {
+               /*
+                * Lock against other receivers so that I don't get stuck in
+                * sbwait() after someone else has received my reply for me.
+                * Also necessary for connection based protocols to avoid
+                * race conditions during a reconnect.
+                */
+               nfs_solock(&nmp->nm_flag);
+               /* Already received, bye bye */
+               if (myrep->r_mrep != NULL) {
+                       nfs_sounlock(&nmp->nm_flag);
+                       return (0);
+               }
+               /*
+                * Get the next Rpc reply off the socket
+                */
+               if (error = nfs_receive(nmp->nm_so, &nam, &mp, myrep)) {
+                       nfs_sounlock(&nmp->nm_flag);
+
+                       /*
+                        * Ignore routing errors on connectionless protocols??
+                        */
+                       if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
+                               nmp->nm_so->so_error = 0;
+                               continue;
+                       }
+
+                       /*
+                        * Otherwise cleanup and return a fatal error.
+                        */
+                       if (myrep->r_flags & R_TIMING) {
+                               myrep->r_flags &= ~R_TIMING;
+                               nmp->nm_rtt = -1;
+                       }
+                       if (myrep->r_flags & R_SENT) {
+                               myrep->r_flags &= ~R_SENT;
+                               nmp->nm_sent--;
+                       }
+                       return (error);
+               }
+       
+               /*
+                * Get the xid and check that it is an rpc reply
+                */
+               m = mp;
+               while (m && m->m_len == 0)
+                       m = m->m_next;
+               if (m == NULL) {
+                       nfsstats.rpcinvalid++;
+                       m_freem(mp);
+                       nfs_sounlock(&nmp->nm_flag);
+                       continue;
+               }
+               bcopy(mtod(m, caddr_t), (caddr_t)&rxid, NFSX_UNSIGNED);
+               /*
+                * Loop through the request list to match up the reply
+                * Iff no match, just drop the datagram
+                */
+               m = mp;
+               rep = nfsreqh.r_next;
+               while (rep != &nfsreqh) {
+                       if (rep->r_mrep == NULL && rxid == rep->r_xid) {
+                               /* Found it.. */
+                               rep->r_mrep = m;
+                               /*
+                                * Update timing
+                                */
+                               if (rep->r_flags & R_TIMING) {
+                                       nfs_updatetimer(rep->r_nmp);
+                                       rep->r_flags &= ~R_TIMING;
+                                       rep->r_nmp->nm_rtt = -1;
+                               }
+                               if (rep->r_flags & R_SENT) {
+                                       rep->r_flags &= ~R_SENT;
+                                       rep->r_nmp->nm_sent--;
+                               }
+                               break;
+                       }
+                       rep = rep->r_next;
+               }
+               nfs_sounlock(&nmp->nm_flag);
+               if (nam)
+                       m_freem(nam);
+               /*
+                * If not matched to a request, drop it.
+                * If it's mine, get out.
+                */
+               if (rep == &nfsreqh) {
+                       nfsstats.rpcunexpected++;
+                       m_freem(m);
+               } else if (rep == myrep)
+                       return (0);
+       }
+}
+
+/*
+ * nfs_request - goes something like this
+ *     - fill in request struct
+ *     - links it into list
+ *     - calls nfs_send() for first transmit
+ *     - calls nfs_receive() to get reply
+ *     - break down rpc header and return with nfs reply pointed to
+ *       by mrep or error
+ * nb: always frees up mreq mbuf list
+ */
+nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
+       struct vnode *vp;
+       struct mbuf *mreq;
+       u_long xid;
+       int procnum;
+       struct proc *procp;
+       int tryhard;
+       struct mount *mp;
+       struct mbuf **mrp;
+       struct mbuf **mdp;
+       caddr_t *dposp;
+{
+       register struct mbuf *m, *mrep;
+       register struct nfsreq *rep;
+       register u_long *tl;
+       register int len;
+       struct nfsmount *nmp;
+       struct mbuf *md;
+       struct nfsreq *reph;
+       caddr_t dpos;
+       char *cp2;
+       int t1;
+       int s, compressed;
+       int error = 0;
+
+       nmp = VFSTONFS(mp);
+       m = mreq;
+       MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
+       rep->r_xid = xid;
+       rep->r_nmp = nmp;
+       rep->r_vp = vp;
+       rep->r_procp = procp;
+       if ((nmp->nm_flag & NFSMNT_SOFT) ||
+           ((nmp->nm_flag & NFSMNT_SPONGY) && !tryhard))
+               rep->r_retry = nmp->nm_retry;
+       else
+               rep->r_retry = NFS_MAXREXMIT + 1;       /* past clip limit */
+       rep->r_flags = rep->r_rexmit = 0;
+       /*
+        * Three cases:
+        * - non-idempotent requests on SOCK_DGRAM use NFS_MINIDEMTIMEO
+        * - idempotent requests on SOCK_DGRAM use 0
+        * - Reliable transports, NFS_RELIABLETIMEO
+        *   Timeouts are still done on reliable transports to ensure detection
+        *   of excessive connection delay.
+        */
+       if (nmp->nm_sotype != SOCK_DGRAM)
+               rep->r_timerinit = -NFS_RELIABLETIMEO;
+       else if (nonidempotent[procnum])
+               rep->r_timerinit = -NFS_MINIDEMTIMEO;
+       else
+               rep->r_timerinit = 0;
+       rep->r_timer = rep->r_timerinit;
+       rep->r_mrep = NULL;
+       len = 0;
+       while (m) {
+               len += m->m_len;
+               m = m->m_next;
+       }
+       mreq->m_pkthdr.len = len;
+       mreq->m_pkthdr.rcvif = (struct ifnet *)0;
+       compressed = 0;
+       m = mreq;
+       if ((nmp->nm_flag & NFSMNT_COMPRESS) && compressrequest[procnum]) {
+               mreq = nfs_compress(mreq);
+               if (mreq != m) {
+                       len = mreq->m_pkthdr.len;
+                       compressed++;
+               }
+       }
+       /*
+        * For non-atomic protocols, insert a Sun RPC Record Mark.
+        */
+       if ((nmp->nm_soflags & PR_ATOMIC) == 0) {
+               M_PREPEND(mreq, sizeof(u_long), M_WAIT);
+               *mtod(mreq, u_long *) = htonl(0x80000000 | len);
+       }
+       rep->r_mreq = mreq;
+
+       /*
+        * Do the client side RPC.
+        */
+       nfsstats.rpcrequests++;
+       /*
+        * Chain request into list of outstanding requests. Be sure
+        * to put it LAST so timer finds oldest requests first.
+        */
+       s = splnet();
+       reph = &nfsreqh;
+       reph->r_prev->r_next = rep;
+       rep->r_prev = reph->r_prev;
+       reph->r_prev = rep;
+       rep->r_next = reph;
+       /*
+        * If backing off another request or avoiding congestion, don't
+        * send this one now but let timer do it. If not timing a request,
+        * do it now.
+        */
+       if (nmp->nm_sent <= 0 || nmp->nm_sotype != SOCK_DGRAM ||
+           (nmp->nm_currexmit == 0 && nmp->nm_sent < nmp->nm_window)) {
+               nmp->nm_sent++;
+               rep->r_flags |= R_SENT;
+               if (nmp->nm_rtt == -1) {
+                       nmp->nm_rtt = 0;
+                       rep->r_flags |= R_TIMING;
+               }
+               splx(s);
+               m = m_copym(mreq, 0, M_COPYALL, M_WAIT);
+               if (nmp->nm_soflags & PR_CONNREQUIRED)
+                       nfs_solock(&nmp->nm_flag);
+               error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);
+               if (nmp->nm_soflags & PR_CONNREQUIRED)
+                       nfs_sounlock(&nmp->nm_flag);
+               if (error && NFSIGNORE_SOERROR(nmp->nm_soflags, error))
+                       nmp->nm_so->so_error = error = 0;
+       } else
+               splx(s);
+
+       /*
+        * Wait for the reply from our send or the timer's.
+        */
+       if (!error)
+               error = nfs_reply(nmp, rep);
+
+       /*
+        * RPC done, unlink the request.
+        */
+       s = splnet();
+       rep->r_prev->r_next = rep->r_next;
+       rep->r_next->r_prev = rep->r_prev;
+       splx(s);
+
+       /*
+        * If there was a successful reply and a tprintf msg.
+        * tprintf a response.
+        */
+       if (!error && (rep->r_flags & R_TPRINTFMSG))
+               nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
+                   "is alive again");
+       m_freem(rep->r_mreq);
+       mrep = rep->r_mrep;
+       FREE((caddr_t)rep, M_NFSREQ);
+       if (error)
+               return (error);
+
+       if (compressed)
+               mrep = nfs_uncompress(mrep);
+       md = mrep;
+       /*
+        * break down the rpc header and check if ok
+        */
+       dpos = mtod(md, caddr_t);
+       nfsm_disect(tl, u_long *, 5*NFSX_UNSIGNED);
+       tl += 2;
+       if (*tl++ == rpc_msgdenied) {
+               if (*tl == rpc_mismatch)
+                       error = EOPNOTSUPP;
+               else
+                       error = EACCES;
+               m_freem(mrep);
+               return (error);
+       }
+       /*
+        * skip over the auth_verf, someday we may want to cache auth_short's
+        * for nfs_reqhead(), but for now just dump it
+        */
+       if (*++tl != 0) {
+               len = nfsm_rndup(fxdr_unsigned(long, *tl));
+               nfsm_adv(len);
+       }
+       nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+       /* 0 == ok */
+       if (*tl == 0) {
+               nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
+               if (*tl != 0) {
+                       error = fxdr_unsigned(int, *tl);
+                       m_freem(mrep);
+                       return (error);
+               }
+               *mrp = mrep;
+               *mdp = md;
+               *dposp = dpos;
+               return (0);
+       }
+       m_freem(mrep);
+       return (EPROTONOSUPPORT);
+nfsmout:
+       return (error);
+}
+
+/*
+ * Get a request for the server main loop
+ * - receive a request via. nfs_soreceive()
+ * - verify it
+ * - fill in the cred struct.
+ */
+nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
+       msk, mtch, wascomp)
+       struct socket *so;
+       u_long prog;
+       u_long vers;
+       int maxproc;
+       struct mbuf **nam;
+       struct mbuf **mrp;
+       struct mbuf **mdp;
+       caddr_t *dposp;
+       u_long *retxid;
+       u_long *procnum;
+       register struct ucred *cr;
+       struct mbuf *msk, *mtch;
+       int *wascomp;
+{
+       register int i;
+       register u_long *tl;
+       register long t1;
+       caddr_t dpos, cp2;
+       int error = 0;
+       struct mbuf *mrep, *md;
+       int len;
+
+       if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+               error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
+       } else {
+               mrep = (struct mbuf *)0;
+               do {
+                       if (mrep) {
+                               m_freem(*nam);
+                               m_freem(mrep);
+                       }
+                       error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
+               } while (!error && nfs_badnam(*nam, msk, mtch));
+       }
+       if (error)
+               return (error);
+       md = mrep;
+       mrep = nfs_uncompress(mrep);
+       if (mrep != md) {
+               *wascomp = 1;
+               md = mrep;
+       } else
+               *wascomp = 0;
+       dpos = mtod(mrep, caddr_t);
+       nfsm_disect(tl, u_long *, 10*NFSX_UNSIGNED);
+       *retxid = *tl++;
+       if (*tl++ != rpc_call) {
+               m_freem(mrep);
+               return (ERPCMISMATCH);
+       }
+       if (*tl++ != rpc_vers) {
+               m_freem(mrep);
+               return (ERPCMISMATCH);
+       }
+       if (*tl++ != prog) {
+               m_freem(mrep);
+               return (EPROGUNAVAIL);
+       }
+       if (*tl++ != vers) {
+               m_freem(mrep);
+               return (EPROGMISMATCH);
+       }
+       *procnum = fxdr_unsigned(u_long, *tl++);
+       if (*procnum == NFSPROC_NULL) {
+               *mrp = mrep;
+               return (0);
+       }
+       if (*procnum > maxproc || *tl++ != rpc_auth_unix) {
+               m_freem(mrep);
+               return (EPROCUNAVAIL);
+       }
+       len = fxdr_unsigned(int, *tl++);
+       if (len < 0 || len > RPCAUTH_MAXSIZ) {
+               m_freem(mrep);
+               return (EBADRPC);
+       }
+       len = fxdr_unsigned(int, *++tl);
+       if (len < 0 || len > NFS_MAXNAMLEN) {
+               m_freem(mrep);
+               return (EBADRPC);
+       }
+       nfsm_adv(nfsm_rndup(len));
+       nfsm_disect(tl, u_long *, 3*NFSX_UNSIGNED);
+       cr->cr_uid = fxdr_unsigned(uid_t, *tl++);
+       cr->cr_gid = fxdr_unsigned(gid_t, *tl++);
+       len = fxdr_unsigned(int, *tl);
+       if (len < 0 || len > RPCAUTH_UNIXGIDS) {
+               m_freem(mrep);
+               return (EBADRPC);
+       }
+       nfsm_disect(tl, u_long *, (len + 2)*NFSX_UNSIGNED);
+       for (i = 1; i <= len; i++)
+               if (i < NGROUPS)
+                       cr->cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
+               else
+                       tl++;
+       cr->cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
+       /*
+        * Do we have any use for the verifier.
+        * According to the "Remote Procedure Call Protocol Spec." it
+        * should be AUTH_NULL, but some clients make it AUTH_UNIX?
+        * For now, just skip over it
+        */
+       len = fxdr_unsigned(int, *++tl);
+       if (len < 0 || len > RPCAUTH_MAXSIZ) {
+               m_freem(mrep);
+               return (EBADRPC);
+       }
+       if (len > 0)
+               nfsm_adv(nfsm_rndup(len));
+       *mrp = mrep;
+       *mdp = md;
+       *dposp = dpos;
+       return (0);
+nfsmout:
+       return (error);
+}
+
+/*
+ * Generate the rpc reply header
+ * siz arg. is used to decide if adding a cluster is worthwhile
+ */
+nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
+       int siz;
+       u_long retxid;
+       int err;
+       struct mbuf **mrq;
+       struct mbuf **mbp;
+       caddr_t *bposp;
+{
+       register u_long *tl;
+       register long t1;
+       caddr_t bpos;
+       struct mbuf *mreq, *mb, *mb2;
+
+       NFSMGETHDR(mreq);
+       mb = mreq;
+       if ((siz+RPC_REPLYSIZ) > MHLEN)
+               MCLGET(mreq, M_WAIT);
+       tl = mtod(mreq, u_long *);
+       mreq->m_len = 6*NFSX_UNSIGNED;
+       bpos = ((caddr_t)tl)+mreq->m_len;
+       *tl++ = retxid;
+       *tl++ = rpc_reply;
+       if (err == ERPCMISMATCH) {
+               *tl++ = rpc_msgdenied;
+               *tl++ = rpc_mismatch;
+               *tl++ = txdr_unsigned(2);
+               *tl = txdr_unsigned(2);
+       } else {
+               *tl++ = rpc_msgaccepted;
+               *tl++ = 0;
+               *tl++ = 0;
+               switch (err) {
+               case EPROGUNAVAIL:
+                       *tl = txdr_unsigned(RPC_PROGUNAVAIL);
+                       break;
+               case EPROGMISMATCH:
+                       *tl = txdr_unsigned(RPC_PROGMISMATCH);
+                       nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+                       *tl++ = txdr_unsigned(2);
+                       *tl = txdr_unsigned(2); /* someday 3 */
+                       break;
+               case EPROCUNAVAIL:
+                       *tl = txdr_unsigned(RPC_PROCUNAVAIL);
+                       break;
+               default:
+                       *tl = 0;
+                       if (err != VNOVAL) {
+                               nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+                               *tl = txdr_unsigned(err);
+                       }
+                       break;
+               };
+       }
+       *mrq = mreq;
+       *mbp = mb;
+       *bposp = bpos;
+       if (err != 0 && err != VNOVAL)
+               nfsstats.srvrpc_errs++;
+       return (0);
+}
+
+/*
+ * Nfs timer routine
+ * Scan the nfsreq list and retranmit any requests that have timed out
+ * To avoid retransmission attempts on STREAM sockets (in the future) make
+ * sure to set the r_retry field to 0 (implies nm_retry == 0).
+ */
+nfs_timer()
+{
+       register struct nfsreq *rep;
+       register struct mbuf *m;
+       register struct socket *so;
+       register struct nfsmount *nmp;
+       int s, error;
+
+       s = splnet();
+       for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) {
+               nmp = rep->r_nmp;
+               if (rep->r_mrep || (rep->r_flags & R_SOFTTERM) ||
+                   (so = nmp->nm_so) == NULL)
+                       continue;
+               if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp)) {
+                       rep->r_flags |= R_SOFTTERM;
+                       continue;
+               }
+               if (rep->r_flags & R_TIMING)    /* update rtt in mount */
+                       nmp->nm_rtt++;
+               /* If not timed out */
+               if (++rep->r_timer < nmp->nm_rto)
+                       continue;
+               /* Do backoff and save new timeout in mount */
+               if (rep->r_flags & R_TIMING) {
+                       nfs_backofftimer(nmp);
+                       rep->r_flags &= ~R_TIMING;
+                       nmp->nm_rtt = -1;
+               }
+               if (rep->r_flags & R_SENT) {
+                       rep->r_flags &= ~R_SENT;
+                       nmp->nm_sent--;
+               }
+
+               /*
+                * Check for too many retries on soft mount.
+                * nb: For hard mounts, r_retry == NFS_MAXREXMIT+1
+                */
+               if (++rep->r_rexmit > NFS_MAXREXMIT)
+                       rep->r_rexmit = NFS_MAXREXMIT;
+
+               /*
+                * Check for server not responding
+                */
+               if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
+                    rep->r_rexmit > NFS_FISHY) {
+                       nfs_msg(rep->r_procp,
+                           nmp->nm_mountp->mnt_stat.f_mntfromname,
+                           "not responding");
+                       rep->r_flags |= R_TPRINTFMSG;
+               }
+               if (rep->r_rexmit >= rep->r_retry) {    /* too many */
+                       nfsstats.rpctimeouts++;
+                       rep->r_flags |= R_SOFTTERM;
+                       continue;
+               }
+               if (nmp->nm_sotype != SOCK_DGRAM)
+                       continue;
+
+               /*
+                * If there is enough space and the window allows..
+                *      Resend it
+                */
+               if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
+                      nmp->nm_sent < nmp->nm_window &&
+                      (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
+                       nfsstats.rpcretries++;
+                       if ((nmp->nm_flag & NFSMNT_NOCONN) == 0)
+                           error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
+                           (caddr_t)0, (struct mbuf *)0, (struct mbuf *)0);
+                       else
+                           error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
+                           nmp->nm_nam, (struct mbuf *)0, (struct mbuf *)0);
+                       if (error) {
+                               if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
+                                       so->so_error = 0;
+                       } else {
+                               /*
+                                * We need to time the request even though we
+                                * are retransmitting.
+                                */
+                               nmp->nm_rtt = 0;
+                               nmp->nm_sent++;
+                               rep->r_flags |= (R_SENT|R_TIMING);
+                               rep->r_timer = rep->r_timerinit;
+                       }
+               }
+       }
+       splx(s);
+       timeout(nfs_timer, (caddr_t)0, hz/NFS_HZ);
+}
+
+/*
+ * NFS timer update and backoff. The "Jacobson/Karels/Karn" scheme is
+ * used here. The timer state is held in the nfsmount structure and
+ * a single request is used to clock the response. When successful
+ * the rtt smoothing in nfs_updatetimer is used, when failed the backoff
+ * is done by nfs_backofftimer. We also log failure messages in these
+ * routines.
+ *
+ * Congestion variables are held in the nfshost structure which
+ * is referenced by nfsmounts and shared per-server. This separation
+ * makes it possible to do per-mount timing which allows varying disk
+ * access times to be dealt with, while preserving a network oriented
+ * congestion control scheme.
+ *
+ * The windowing implements the Jacobson/Karels slowstart algorithm
+ * with adjusted scaling factors. We start with one request, then send
+ * 4 more after each success until the ssthresh limit is reached, then
+ * we increment at a rate proportional to the window. On failure, we
+ * remember 3/4 the current window and clamp the send limit to 1. Note
+ * ICMP source quench is not reflected in so->so_error so we ignore that
+ * for now.
+ *
+ * NFS behaves much more like a transport protocol with these changes,
+ * shedding the teenage pedal-to-the-metal tendencies of "other"
+ * implementations.
+ *
+ * Timers and congestion avoidance by Tom Talpey, Open Software Foundation.
+ */
+
+/*
+ * The TCP algorithm was not forgiving enough. Because the NFS server
+ * responds only after performing lookups/diskio/etc, we have to be
+ * more prepared to accept a spiky variance. The TCP algorithm is:
+ * TCP_RTO(nmp) ((((nmp)->nm_srtt >> 2) + (nmp)->nm_rttvar) >> 1)
+ */
+#define NFS_RTO(nmp)   (((nmp)->nm_srtt >> 3) + (nmp)->nm_rttvar)
+
+nfs_updatetimer(nmp)
+       register struct nfsmount *nmp;
+{
+
+       /* If retransmitted, clear and return */
+       if (nmp->nm_rexmit || nmp->nm_currexmit) {
+               nmp->nm_rexmit = nmp->nm_currexmit = 0;
+               return;
+       }
+       /* If have a measurement, do smoothing */
+       if (nmp->nm_srtt) {
+               register short delta;
+               delta = nmp->nm_rtt - (nmp->nm_srtt >> 3);
+               if ((nmp->nm_srtt += delta) <= 0)
+                       nmp->nm_srtt = 1;
+               if (delta < 0)
+                       delta = -delta;
+               delta -= (nmp->nm_rttvar >> 2);
+               if ((nmp->nm_rttvar += delta) <= 0)
+                       nmp->nm_rttvar = 1;
+       /* Else initialize */
+       } else {
+               nmp->nm_rttvar = nmp->nm_rtt << 1;
+               if (nmp->nm_rttvar == 0) nmp->nm_rttvar = 2;
+               nmp->nm_srtt = nmp->nm_rttvar << 2;
+       }
+       /* Compute new Retransmission TimeOut and clip */
+       nmp->nm_rto = NFS_RTO(nmp);
+       if (nmp->nm_rto < NFS_MINTIMEO)
+               nmp->nm_rto = NFS_MINTIMEO;
+       else if (nmp->nm_rto > NFS_MAXTIMEO)
+               nmp->nm_rto = NFS_MAXTIMEO;
+
+       /* Update window estimate */
+       if (nmp->nm_window < nmp->nm_ssthresh)  /* quickly */
+               nmp->nm_window += 4;
+       else {                                          /* slowly */
+               register long incr = ++nmp->nm_winext;
+               incr = (incr * incr) / nmp->nm_window;
+               if (incr > 0) {
+                       nmp->nm_winext = 0;
+                       ++nmp->nm_window;
+               }
+       }
+       if (nmp->nm_window > NFS_MAXWINDOW)
+               nmp->nm_window = NFS_MAXWINDOW;
+}
+
+nfs_backofftimer(nmp)
+       register struct nfsmount *nmp;
+{
+       register unsigned long newrto;
+
+       /* Clip shift count */
+       if (++nmp->nm_rexmit > 8 * sizeof nmp->nm_rto)
+               nmp->nm_rexmit = 8 * sizeof nmp->nm_rto;
+       /* Back off RTO exponentially */
+       newrto = NFS_RTO(nmp);
+       newrto <<= (nmp->nm_rexmit - 1);
+       if (newrto == 0 || newrto > NFS_MAXTIMEO)
+               newrto = NFS_MAXTIMEO;
+       nmp->nm_rto = newrto;
+
+       /* If too many retries, message, assume a bogus RTT and re-measure */
+       if (nmp->nm_currexmit < nmp->nm_rexmit) {
+               nmp->nm_currexmit = nmp->nm_rexmit;
+               if (nmp->nm_currexmit >= nfsrexmtthresh) {
+                       if (nmp->nm_currexmit == nfsrexmtthresh) {
+                               nmp->nm_rttvar += (nmp->nm_srtt >> 2);
+                               nmp->nm_srtt = 0;
+                       }
+               }
+       }
+       /* Close down window but remember this point (3/4 current) for later */
+       nmp->nm_ssthresh = ((nmp->nm_window << 1) + nmp->nm_window) >> 2;
+       nmp->nm_window = 1;
+       nmp->nm_winext = 0;
+}
+
+/*
+ * Test for a termination signal pending on procp.
+ * This is used for NFSMNT_INT mounts.
+ */
+nfs_sigintr(p)
+       register struct proc *p;
+{
+       if (p && p->p_sig && (((p->p_sig &~ p->p_sigmask) &~ p->p_sigignore) &
+           NFSINT_SIGMASK))
+               return (1);
+       else
+               return (0);
+}
+
+nfs_msg(p, server, msg)
+       struct proc *p;
+       char *server, *msg;
+{
+       tpr_t tpr;
+
+       if (p)
+               tpr = tprintf_open(p);
+       else
+               tpr = NULL;
+       tprintf(tpr, "nfs server %s: %s\n", server, msg);
+       tprintf_close(tpr);
+}
+
+/*
+ * Lock a socket against others.
+ * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
+ * and also to avoid race conditions between the processes with nfs requests
+ * in progress when a reconnect is necessary.
+ */
+nfs_solock(flagp)
+       register int *flagp;
+{
+
+       while (*flagp & NFSMNT_SCKLOCK) {
+               *flagp |= NFSMNT_WANTSCK;
+               (void) tsleep((caddr_t)flagp, PZERO-1, "nfsolck", 0);
+       }
+       *flagp |= NFSMNT_SCKLOCK;
+}
+
+/*
+ * Unlock the stream socket for others.
+ */
+nfs_sounlock(flagp)
+       register int *flagp;
+{
+
+       if ((*flagp & NFSMNT_SCKLOCK) == 0)
+               panic("nfs sounlock");
+       *flagp &= ~NFSMNT_SCKLOCK;
+       if (*flagp & NFSMNT_WANTSCK) {
+               *flagp &= ~NFSMNT_WANTSCK;
+               wakeup((caddr_t)flagp);
+       }
+}
+
+/*
+ * This function compares two net addresses by family and returns TRUE
+ * if they are the same.
+ * If there is any doubt, return FALSE.
+ */
+nfs_netaddr_match(nam1, nam2)
+       struct mbuf *nam1, *nam2;
+{
+       register struct sockaddr *saddr1, *saddr2;
+
+       saddr1 = mtod(nam1, struct sockaddr *);
+       saddr2 = mtod(nam2, struct sockaddr *);
+       if (saddr1->sa_family != saddr2->sa_family)
+               return (0);
+
+       /*
+        * Must do each address family separately since unused fields
+        * are undefined values and not always zeroed.
+        */
+       switch (saddr1->sa_family) {
+       case AF_INET:
+               if (((struct sockaddr_in *)saddr1)->sin_addr.s_addr ==
+                   ((struct sockaddr_in *)saddr2)->sin_addr.s_addr)
+                       return (1);
+               break;
+       default:
+               break;
+       };
+       return (0);
+}
+
+/*
+ * Check the hostname fields for nfsd's mask and match fields.
+ * By address family:
+ * - Bitwise AND the mask with the host address field
+ * - Compare for == with match
+ * return TRUE if not equal
+ */
+nfs_badnam(nam, msk, mtch)
+       register struct mbuf *nam, *msk, *mtch;
+{
+       switch (mtod(nam, struct sockaddr *)->sa_family) {
+       case AF_INET:
+               return ((mtod(nam, struct sockaddr_in *)->sin_addr.s_addr &
+                        mtod(msk, struct sockaddr_in *)->sin_addr.s_addr) !=
+                        mtod(mtch, struct sockaddr_in *)->sin_addr.s_addr);
+       default:
+               printf("nfs_badmatch, unknown sa_family\n");
+               return (0);
+       };
+}
diff --git a/usr/src/sys.386bsd/nfs/nfs_srvcache.c b/usr/src/sys.386bsd/nfs/nfs_srvcache.c
new file mode 100644 (file)
index 0000000..b274b17
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs_srvcache.c      7.11 (Berkeley) 4/16/91
+ */
+
+/*
+ * Reference: Chet Juszczak, "Improving the Performance and Correctness
+ *            of an NFS Server", in Proc. Winter 1989 USENIX Conference,
+ *            pages 53-63. San Diego, February 1989.
+ */
+
+#include "param.h"
+#include "namei.h"
+#include "vnode.h"
+#include "mount.h"
+#include "kernel.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+
+#include "../netinet/in.h"
+
+#include "nfsm_subs.h"
+#include "nfsv2.h"
+#include "nfsrvcache.h"
+#include "nfs.h"
+
+#if    ((NFSRCHSZ&(NFSRCHSZ-1)) == 0)
+#define        NFSRCHASH(xid)          (((xid)+((xid)>>16))&(NFSRCHSZ-1))
+#else
+#define        NFSRCHASH(xid)          (((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ)
+#endif
+
+union rhead {
+       union  rhead *rh_head[2];
+       struct nfsrvcache *rh_chain[2];
+} rhead[NFSRCHSZ];
+
+static struct nfsrvcache nfsrvcachehead;
+static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ];
+
+#define TRUE   1
+#define        FALSE   0
+
+/*
+ * Static array that defines which nfs rpc's are nonidempotent
+ */
+int nonidempotent[NFS_NPROCS] = {
+       FALSE,
+       FALSE,
+       TRUE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       FALSE,
+       FALSE,
+};
+
+/* True iff the rpc reply is an nfs status ONLY! */
+static int repliesstatus[NFS_NPROCS] = {
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       FALSE,
+       TRUE,
+       FALSE,
+       FALSE,
+};
+
+/*
+ * Initialize the server request cache list
+ */
+nfsrv_initcache()
+{
+       register int i;
+       register struct nfsrvcache *rp = nfsrvcache;
+       register struct nfsrvcache *hp = &nfsrvcachehead;
+       register union  rhead *rh = rhead;
+
+       for (i = NFSRCHSZ; --i >= 0; rh++) {
+               rh->rh_head[0] = rh;
+               rh->rh_head[1] = rh;
+       }
+       hp->rc_next = hp->rc_prev = hp;
+       for (i = NFSRVCACHESIZ; i-- > 0; ) {
+               rp->rc_state = RC_UNUSED;
+               rp->rc_flag = 0;
+               rp->rc_forw = rp;
+               rp->rc_back = rp;
+               rp->rc_next = hp->rc_next;
+               hp->rc_next->rc_prev = rp;
+               rp->rc_prev = hp;
+               hp->rc_next = rp;
+               rp++;
+       }
+}
+
+/*
+ * Look for the request in the cache
+ * If found then
+ *    return action and optionally reply
+ * else
+ *    insert it in the cache
+ *
+ * The rules are as follows:
+ * - if in progress, return DROP request
+ * - if completed within DELAY of the current time, return DROP it
+ * - if completed a longer time ago return REPLY if the reply was cached or
+ *   return DOIT
+ * Update/add new request at end of lru list
+ */
+nfsrv_getcache(nam, xid, proc, repp)
+       struct mbuf *nam;
+       u_long xid;
+       int proc;
+       struct mbuf **repp;
+{
+       register struct nfsrvcache *rp;
+       register union  rhead *rh;
+       struct mbuf *mb;
+       caddr_t bpos;
+       int ret;
+
+       rh = &rhead[NFSRCHASH(xid)];
+loop:
+       for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
+               if (xid == rp->rc_xid && proc == rp->rc_proc &&
+                   nfs_netaddr_match(nam, &rp->rc_nam)) {
+                       if ((rp->rc_flag & RC_LOCKED) != 0) {
+                               rp->rc_flag |= RC_WANTED;
+                               (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
+                               goto loop;
+                       }
+                       rp->rc_flag |= RC_LOCKED;
+                       put_at_head(rp);
+                       if (rp->rc_state == RC_UNUSED)
+                               panic("nfsrv cache");
+                       if (rp->rc_state == RC_INPROG ||
+                          (time.tv_sec - rp->rc_timestamp) < RC_DELAY) {
+                               nfsstats.srvcache_inproghits++;
+                               ret = RC_DROPIT;
+                       } else if (rp->rc_flag & RC_REPSTATUS) {
+                               nfsstats.srvcache_idemdonehits++;
+                               nfs_rephead(0, xid, rp->rc_status, repp, &mb,
+                                       &bpos);
+                               rp->rc_timestamp = time.tv_sec;
+                               ret = RC_REPLY;
+                       } else if (rp->rc_flag & RC_REPMBUF) {
+                               nfsstats.srvcache_idemdonehits++;
+                               *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
+                                               M_WAIT);
+                               rp->rc_timestamp = time.tv_sec;
+                               ret = RC_REPLY;
+                       } else {
+                               nfsstats.srvcache_nonidemdonehits++;
+                               rp->rc_state = RC_INPROG;
+                               ret = RC_DOIT;
+                       }
+                       rp->rc_flag &= ~RC_LOCKED;
+                       if (rp->rc_flag & RC_WANTED) {
+                               rp->rc_flag &= ~RC_WANTED;
+                               wakeup((caddr_t)rp);
+                       }
+                       return (ret);
+               }
+       }
+       nfsstats.srvcache_misses++;
+       rp = nfsrvcachehead.rc_prev;
+       while ((rp->rc_flag & RC_LOCKED) != 0) {
+               rp->rc_flag |= RC_WANTED;
+               (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
+       }
+       remque(rp);
+       put_at_head(rp);
+       if (rp->rc_flag & RC_REPMBUF)
+               mb = rp->rc_reply;
+       else
+               mb = (struct mbuf *)0;
+       rp->rc_flag = 0;
+       rp->rc_state = RC_INPROG;
+       rp->rc_xid = xid;
+       bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf));
+       rp->rc_proc = proc;
+       insque(rp, rh);
+       if (mb)
+               m_freem(mb);
+       return (RC_DOIT);
+}
+
+/*
+ * Update a request cache entry after the rpc has been done
+ */
+nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf)
+       struct mbuf *nam;
+       u_long xid;
+       int proc;
+       int repvalid;
+       int repstat;
+       struct mbuf *repmbuf;
+{
+       register struct nfsrvcache *rp;
+       register union  rhead *rh;
+
+       rh = &rhead[NFSRCHASH(xid)];
+loop:
+       for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
+               if (xid == rp->rc_xid && proc == rp->rc_proc &&
+                   nfs_netaddr_match(nam, &rp->rc_nam)) {
+                       if ((rp->rc_flag & RC_LOCKED) != 0) {
+                               rp->rc_flag |= RC_WANTED;
+                               (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
+                               goto loop;
+                       }
+                       rp->rc_flag |= RC_LOCKED;
+                       rp->rc_state = RC_DONE;
+                       /*
+                        * If we have a valid reply update status and save
+                        * the reply for non-idempotent rpc's.
+                        * Otherwise invalidate entry by setting the timestamp
+                        * to nil.
+                        */
+                       if (repvalid) {
+                               rp->rc_timestamp = time.tv_sec;
+                               if (nonidempotent[proc]) {
+                                       if (repliesstatus[proc]) {
+                                               rp->rc_status = repstat;
+                                               rp->rc_flag |= RC_REPSTATUS;
+                                       } else {
+                                               rp->rc_reply = m_copym(repmbuf,
+                                                       0, M_COPYALL, M_WAIT);
+                                               rp->rc_flag |= RC_REPMBUF;
+                                       }
+                               }
+                       } else {
+                               rp->rc_timestamp = 0;
+                       }
+                       rp->rc_flag &= ~RC_LOCKED;
+                       if (rp->rc_flag & RC_WANTED) {
+                               rp->rc_flag &= ~RC_WANTED;
+                               wakeup((caddr_t)rp);
+                       }
+                       return;
+               }
+       }
+}
diff --git a/usr/src/sys.386bsd/nfs/nfs_syscalls.c b/usr/src/sys.386bsd/nfs/nfs_syscalls.c
new file mode 100644 (file)
index 0000000..c6d93c9
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs_syscalls.c      7.26 (Berkeley) 4/16/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "file.h"
+#include "stat.h"
+#include "namei.h"
+#include "vnode.h"
+#include "mount.h"
+#include "proc.h"
+#include "malloc.h"
+#include "buf.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "domain.h"
+#include "protosw.h"
+
+#include "../netinet/in.h"
+#include "../netinet/tcp.h"
+
+#include "nfsv2.h"
+#include "nfs.h"
+#include "nfsrvcache.h"
+
+/* Global defs. */
+extern u_long nfs_prog, nfs_vers;
+extern int (*nfsrv_procs[NFS_NPROCS])();
+extern struct buf nfs_bqueue;
+extern int nfs_numasync;
+extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
+extern int nfs_tcpnodelay;
+struct mbuf *nfs_compress();
+
+#define        TRUE    1
+#define        FALSE   0
+
+static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
+static int compressreply[NFS_NPROCS] = {
+       FALSE,
+       TRUE,
+       TRUE,
+       FALSE,
+       TRUE,
+       TRUE,
+       FALSE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+};
+/*
+ * NFS server system calls
+ * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
+ */
+
+/*
+ * Get file handle system call
+ */
+/* ARGSUSED */
+getfh(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               char    *fname;
+               fhandle_t *fhp;
+       } *uap;
+       int *retval;
+{
+       register struct nameidata *ndp;
+       register struct vnode *vp;
+       fhandle_t fh;
+       int error;
+       struct nameidata nd;
+
+       /*
+        * Must be super user
+        */
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       ndp = &nd;
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
+       ndp->ni_segflg = UIO_USERSPACE;
+       ndp->ni_dirp = uap->fname;
+       if (error = namei(ndp, p))
+               return (error);
+       vp = ndp->ni_vp;
+       bzero((caddr_t)&fh, sizeof(fh));
+       fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+       error = VFS_VPTOFH(vp, &fh.fh_fid);
+       vput(vp);
+       if (error)
+               return (error);
+       error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
+       return (error);
+}
+
+/*
+ * Nfs server psuedo system call for the nfsd's
+ * Never returns unless it fails or gets killed
+ */
+/* ARGSUSED */
+nfssvc(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int s;
+               caddr_t mskval;
+               int msklen;
+               caddr_t mtchval;
+               int mtchlen;
+       } *uap;
+       int *retval;
+{
+       register struct mbuf *m;
+       register int siz;
+       register struct ucred *cr;
+       struct file *fp;
+       struct mbuf *mreq, *mrep, *nam, *md;
+       struct mbuf msk, mtch;
+       struct socket *so;
+       caddr_t dpos;
+       int procid, repstat, error, cacherep, wascomp;
+       u_long retxid;
+
+       /*
+        * Must be super user
+        */
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       if (error = getsock(p->p_fd, uap->s, &fp))
+               return (error);
+       so = (struct socket *)fp->f_data;
+       if (sosendallatonce(so))
+               siz = NFS_MAXPACKET;
+       else
+               siz = NFS_MAXPACKET + sizeof(u_long);
+       if (error = soreserve(so, siz, siz))
+               goto bad;
+       if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME))
+               goto bad;
+       bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf));
+       msk.m_data = msk.m_dat;
+       m_freem(nam);
+       if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME))
+               goto bad;
+       bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf));
+       mtch.m_data = mtch.m_dat;
+       m_freem(nam);
+
+       /* Copy the cred so others don't see changes */
+       cr = p->p_ucred = crcopy(p->p_ucred);
+
+       /*
+        * Set protocol specific options { for now TCP only } and
+        * reserve some space. For datagram sockets, this can get called
+        * repeatedly for the same socket, but that isn't harmful.
+        */
+       if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+               MGET(m, M_WAIT, MT_SOOPTS);
+               *mtod(m, int *) = 1;
+               m->m_len = sizeof(int);
+               sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
+       }
+       if (so->so_proto->pr_domain->dom_family == AF_INET &&
+           so->so_proto->pr_protocol == IPPROTO_TCP &&
+           nfs_tcpnodelay) {
+               MGET(m, M_WAIT, MT_SOOPTS);
+               *mtod(m, int *) = 1;
+               m->m_len = sizeof(int);
+               sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
+       }
+       so->so_rcv.sb_flags &= ~SB_NOINTR;
+       so->so_rcv.sb_timeo = 0;
+       so->so_snd.sb_flags &= ~SB_NOINTR;
+       so->so_snd.sb_timeo = 0;
+
+       /*
+        * Just loop around doin our stuff until SIGKILL
+        */
+       for (;;) {
+               if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
+                  &nam, &mrep, &md, &dpos, &retxid, &procid, cr,
+                  &msk, &mtch, &wascomp)) {
+                       if (nam)
+                               m_freem(nam);
+                       if (error == EPIPE || error == EINTR ||
+                           error == ERESTART) {
+                               error = 0;
+                               goto bad;
+                       }
+                       so->so_error = 0;
+                       continue;
+               }
+
+               if (nam)
+                       cacherep = nfsrv_getcache(nam, retxid, procid, &mreq);
+               else
+                       cacherep = RC_DOIT;
+               switch (cacherep) {
+               case RC_DOIT:
+                       if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos,
+                               cr, retxid, &mreq, &repstat, p)) {
+                               nfsstats.srv_errs++;
+                               if (nam) {
+                                       nfsrv_updatecache(nam, retxid, procid,
+                                               FALSE, repstat, mreq);
+                                       m_freem(nam);
+                               }
+                               break;
+                       }
+                       nfsstats.srvrpccnt[procid]++;
+                       if (nam)
+                               nfsrv_updatecache(nam, retxid, procid, TRUE,
+                                       repstat, mreq);
+                       mrep = (struct mbuf *)0;
+               case RC_REPLY:
+                       m = mreq;
+                       siz = 0;
+                       while (m) {
+                               siz += m->m_len;
+                               m = m->m_next;
+                       }
+                       if (siz <= 0 || siz > NFS_MAXPACKET) {
+                               printf("mbuf siz=%d\n",siz);
+                               panic("Bad nfs svc reply");
+                       }
+                       mreq->m_pkthdr.len = siz;
+                       mreq->m_pkthdr.rcvif = (struct ifnet *)0;
+                       if (wascomp && compressreply[procid]) {
+                               mreq = nfs_compress(mreq);
+                               siz = mreq->m_pkthdr.len;
+                       }
+                       /*
+                        * For non-atomic protocols, prepend a Sun RPC
+                        * Record Mark.
+                        */
+                       if (!sosendallatonce(so)) {
+                               M_PREPEND(mreq, sizeof(u_long), M_WAIT);
+                               *mtod(mreq, u_long *) = htonl(0x80000000 | siz);
+                       }
+                       error = nfs_send(so, nam, mreq, (struct nfsreq *)0);
+                       if (nam)
+                               m_freem(nam);
+                       if (mrep)
+                               m_freem(mrep);
+                       if (error) {
+                               if (error == EPIPE || error == EINTR ||
+                                   error == ERESTART)
+                                       goto bad;
+                               so->so_error = 0;
+                       }
+                       break;
+               case RC_DROPIT:
+                       m_freem(mrep);
+                       m_freem(nam);
+                       break;
+               };
+       }
+bad:
+       return (error);
+}
+
+/*
+ * Nfs pseudo system call for asynchronous i/o daemons.
+ * These babies just pretend to be disk interrupt service routines
+ * for client nfs. They are mainly here for read ahead/write behind.
+ * Never returns unless it fails or gets killed
+ */
+/* ARGSUSED */
+async_daemon(p, uap, retval)
+       struct proc *p;
+       struct args *uap;
+       int *retval;
+{
+       register struct buf *bp, *dp;
+       register int i, myiod;
+       int error;
+
+       /*
+        * Must be super user
+        */
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       /*
+        * Assign my position or return error if too many already running
+        */
+       myiod = -1;
+       for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
+               if (nfs_asyncdaemon[i] == 0) {
+                       nfs_asyncdaemon[i]++;
+                       myiod = i;
+                       break;
+               }
+       if (myiod == -1)
+               return (EBUSY);
+       nfs_numasync++;
+       dp = &nfs_bqueue;
+       /*
+        * Just loop around doin our stuff until SIGKILL
+        */
+       for (;;) {
+               while (dp->b_actf == NULL && error == 0) {
+                       nfs_iodwant[myiod] = p;
+                       error = tsleep((caddr_t)&nfs_iodwant[myiod],
+                               PWAIT | PCATCH, "nfsidl", 0);
+                       nfs_iodwant[myiod] = (struct proc *)0;
+               }
+               while (dp->b_actf != NULL) {
+                       /* Take one off the end of the list */
+                       bp = dp->b_actl;
+                       if (bp->b_actl == dp) {
+                               dp->b_actf = dp->b_actl = (struct buf *)0;
+                       } else {
+                               dp->b_actl = bp->b_actl;
+                               bp->b_actl->b_actf = dp;
+                       }
+                       (void) nfs_doio(bp);
+               }
+               if (error) {
+                       nfs_asyncdaemon[myiod] = 0;
+                       nfs_numasync--;
+                       return (error);
+               }
+       }
+}
diff --git a/usr/src/sys.386bsd/nfs/nfs_vfsops.c b/usr/src/sys.386bsd/nfs/nfs_vfsops.c
new file mode 100644 (file)
index 0000000..d08c12d
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfs_vfsops.c        7.31 (Berkeley) 5/6/91
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "ioctl.h"
+#include "signal.h"
+#include "proc.h"
+#include "namei.h"
+#include "vnode.h"
+#include "mount.h"
+#include "buf.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "systm.h"
+
+#include "../net/if.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+
+#include "nfsv2.h"
+#include "nfsnode.h"
+#include "nfsmount.h"
+#include "nfs.h"
+#include "xdr_subs.h"
+#include "nfsm_subs.h"
+#include "nfsdiskless.h"
+
+/*
+ * nfs vfs operations.
+ */
+struct vfsops nfs_vfsops = {
+       nfs_mount,
+       nfs_start,
+       nfs_unmount,
+       nfs_root,
+       nfs_quotactl,
+       nfs_statfs,
+       nfs_sync,
+       nfs_fhtovp,
+       nfs_vptofh,
+       nfs_init,
+};
+
+static u_char nfs_mntid;
+extern u_long nfs_procids[NFS_NPROCS];
+extern u_long nfs_prog, nfs_vers;
+struct nfs_diskless nfs_diskless;
+void nfs_disconnect();
+
+#define TRUE   1
+#define        FALSE   0
+
+/*
+ * nfs statfs call
+ */
+nfs_statfs(mp, sbp, p)
+       struct mount *mp;
+       register struct statfs *sbp;
+       struct proc *p;
+{
+       register struct vnode *vp;
+       register struct nfsv2_statfs *sfp;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       struct nfsmount *nmp;
+       struct ucred *cred;
+       struct nfsnode *np;
+
+       nmp = VFSTONFS(mp);
+       if (error = nfs_nget(mp, &nmp->nm_fh, &np))
+               return (error);
+       vp = NFSTOV(np);
+       nfsstats.rpccnt[NFSPROC_STATFS]++;
+       cred = crget();
+       cred->cr_ngroups = 1;
+       nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
+       nfsm_fhtom(vp);
+       nfsm_request(vp, NFSPROC_STATFS, p, 0);
+       nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
+       sbp->f_type = MOUNT_NFS;
+       sbp->f_flags = nmp->nm_flag;
+       sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize);
+       sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize);
+       sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
+       sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
+       sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
+       sbp->f_files = 0;
+       sbp->f_ffree = 0;
+       if (sbp != &mp->mnt_stat) {
+               bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+               bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+       }
+       nfsm_reqdone;
+       nfs_nput(vp);
+       crfree(cred);
+       return (error);
+}
+
+/*
+ * Mount a remote root fs via. nfs. This depends on the info in the
+ * nfs_diskless structure that has been filled in properly by some primary
+ * bootstrap.
+ * It goes something like this:
+ * - do enough of "ifconfig" by calling ifioctl() so that the system
+ *   can talk to the server
+ * - If nfs_diskless.mygateway is filled in, use that address as
+ *   a default gateway.
+ *   (This is done the 4.3 way with rtioctl() and should be changed)
+ * - hand craft the swap nfs vnode hanging off a fake mount point
+ * - build the rootfs mount point and call mountnfs() to do the rest.
+ */
+nfs_mountroot()
+{
+       register struct mount *mp;
+       register struct mbuf *m;
+       struct socket *so;
+       struct vnode *vp;
+       int error;
+
+       /*
+        * Do enough of ifconfig(8) so that critical net interface can
+        * talk to the server.
+        */
+       if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
+               panic("nfs ifconf");
+       if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif))
+               panic("nfs ifconf2");
+       soclose(so);
+
+       /*
+        * If the gateway field is filled in, set it as the default route.
+        */
+#ifdef COMPAT_43
+       if (nfs_diskless.mygateway.sa_family == AF_INET) {
+               struct ortentry rt;
+               struct sockaddr_in *sin;
+
+               sin = (struct sockaddr_in *) &rt.rt_dst;
+               sin->sin_len = sizeof (struct sockaddr_in);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = 0;       /* default */
+               bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway,
+                       sizeof (struct sockaddr_in));
+               rt.rt_flags = (RTF_UP | RTF_GATEWAY);
+               if (rtioctl(SIOCADDRT, (caddr_t)&rt))
+                       panic("nfs root route");
+       }
+#endif /* COMPAT_43 */
+
+       /*
+        * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
+        * Create a fake mount point just for the swap vnode so that the
+        * swap file can be on a different server from the rootfs.
+        */
+       if (swdevt[0].sw_dev == NODEV) {
+               mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+                       M_MOUNT, M_NOWAIT);
+               if (mp == NULL)
+                       panic("nfs root mount");
+               mp->mnt_op = &nfs_vfsops;
+               mp->mnt_flag = 0;
+               mp->mnt_exroot = 0;
+               mp->mnt_mounth = NULLVP;
+       
+               /*
+                * Set up the diskless nfs_args for the swap mount point
+                * and then call mountnfs() to mount it.
+                * Since the swap file is not the root dir of a file system,
+                * hack it to a regular file.
+                */
+               nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
+               MGET(m, MT_SONAME, M_DONTWAIT);
+               if (m == NULL)
+                       panic("nfs root mbuf");
+               bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
+                       nfs_diskless.swap_saddr.sa_len);
+               m->m_len = nfs_diskless.swap_saddr.sa_len;
+               if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
+                       nfs_diskless.swap_hostnam, &vp))
+                       panic("nfs swap");
+               vp->v_type = VREG;
+               vp->v_flag = 0;
+               swapdev_vp = vp;
+               VREF(vp);
+               swdevt[0].sw_vp = vp;
+       }
+
+       /*
+        * Create the rootfs mount point.
+        */
+       mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+               M_MOUNT, M_NOWAIT);
+       if (mp == NULL)
+               panic("nfs root mount2");
+       mp->mnt_op = &nfs_vfsops;
+       mp->mnt_flag = MNT_RDONLY;
+       mp->mnt_exroot = 0;
+       mp->mnt_mounth = NULLVP;
+
+       /*
+        * Set up the root fs args and call mountnfs() to do the rest.
+        */
+       nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
+       MGET(m, MT_SONAME, M_DONTWAIT);
+       if (m == NULL)
+               panic("nfs root mbuf2");
+       bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
+               nfs_diskless.root_saddr.sa_len);
+       m->m_len = nfs_diskless.root_saddr.sa_len;
+       if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
+               nfs_diskless.root_hostnam, &vp))
+               panic("nfs root");
+       if (vfs_lock(mp))
+               panic("nfs root2");
+       rootfs = mp;
+       mp->mnt_next = mp;
+       mp->mnt_prev = mp;
+       mp->mnt_vnodecovered = NULLVP;
+       vfs_unlock(mp);
+       rootvp = vp;
+       inittodr((time_t)0);    /* There is no time in the nfs fsstat so ?? */
+       return (0);
+}
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ * It seems a bit dumb to copyinstr() the host and path here and then
+ * bcopy() them in mountnfs(), but I wanted to detect errors before
+ * doing the sockargs() call because sockargs() allocates an mbuf and
+ * an error after that means that I have to release the mbuf.
+ */
+/* ARGSUSED */
+nfs_mount(mp, path, data, ndp, p)
+       struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+       struct proc *p;
+{
+       int error;
+       struct nfs_args args;
+       struct mbuf *nam;
+       struct vnode *vp;
+       char pth[MNAMELEN], hst[MNAMELEN];
+       u_int len;
+       nfsv2fh_t nfh;
+
+       if (mp->mnt_flag & MNT_UPDATE)
+               return (0);
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
+               return (error);
+       if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
+               return (error);
+       if (error = copyinstr(path, pth, MNAMELEN-1, &len))
+               return (error);
+       bzero(&pth[len], MNAMELEN - len);
+       if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
+               return (error);
+       bzero(&hst[len], MNAMELEN - len);
+       /* sockargs() call must be after above copyin() calls */
+       if (error = sockargs(&nam, (caddr_t)args.addr,
+               sizeof (struct sockaddr), MT_SONAME))
+               return (error);
+       args.fh = &nfh;
+       error = mountnfs(&args, mp, nam, pth, hst, &vp);
+       return (error);
+}
+
+/*
+ * Common code for mount and mountroot
+ */
+mountnfs(argp, mp, nam, pth, hst, vpp)
+       register struct nfs_args *argp;
+       register struct mount *mp;
+       struct mbuf *nam;
+       char *pth, *hst;
+       struct vnode **vpp;
+{
+       register struct nfsmount *nmp;
+       struct proc *p = curproc;               /* XXX */
+       struct nfsnode *np;
+       int error;
+       fsid_t tfsid;
+
+       MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
+       bzero((caddr_t)nmp, sizeof *nmp);
+       mp->mnt_data = (qaddr_t)nmp;
+       /*
+        * Generate a unique nfs mount id. The problem is that a dev number
+        * is not unique across multiple systems. The techique is as follows:
+        * 1) Set to nblkdev,0 which will never be used otherwise
+        * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
+        *      NOT 0
+        * 3) Loop searching the mount list for another one with same id
+        *      If a match, increment val[0] and try again
+        * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
+        *      so that nfs is not limited to 255 mount points
+        *     Incrementing the high order bits does no real harm, since it
+        *     simply makes the major dev number tick up. The upper bound is
+        *     set to major dev 127 to avoid any sign extention problems
+        */
+       mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
+       mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
+       if (++nfs_mntid == 0)
+               ++nfs_mntid;
+       tfsid.val[0] = makedev(nblkdev, nfs_mntid);
+       tfsid.val[1] = MOUNT_NFS;
+       while (rootfs && getvfs(&tfsid)) {
+               tfsid.val[0]++;
+               nfs_mntid++;
+       }
+       if (major(tfsid.val[0]) > 127) {
+               error = ENOENT;
+               goto bad;
+       }
+       mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
+       nmp->nm_mountp = mp;
+       nmp->nm_flag = argp->flags;
+       nmp->nm_rto = NFS_TIMEO;
+       nmp->nm_rtt = -1;
+       nmp->nm_rttvar = nmp->nm_rto << 1;
+       nmp->nm_retry = NFS_RETRANS;
+       nmp->nm_wsize = NFS_WSIZE;
+       nmp->nm_rsize = NFS_RSIZE;
+       bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
+       bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
+       bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
+       nmp->nm_nam = nam;
+
+       if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
+               nmp->nm_rto = argp->timeo;
+               /* NFS timeouts are specified in 1/10 sec. */
+               nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
+               if (nmp->nm_rto < NFS_MINTIMEO)
+                       nmp->nm_rto = NFS_MINTIMEO;
+               else if (nmp->nm_rto > NFS_MAXTIMEO)
+                       nmp->nm_rto = NFS_MAXTIMEO;
+               nmp->nm_rttvar = nmp->nm_rto << 1;
+       }
+
+       if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
+               nmp->nm_retry = argp->retrans;
+               if (nmp->nm_retry > NFS_MAXREXMIT)
+                       nmp->nm_retry = NFS_MAXREXMIT;
+       }
+
+       if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
+               nmp->nm_wsize = argp->wsize;
+               /* Round down to multiple of blocksize */
+               nmp->nm_wsize &= ~0x1ff;
+               if (nmp->nm_wsize <= 0)
+                       nmp->nm_wsize = 512;
+               else if (nmp->nm_wsize > NFS_MAXDATA)
+                       nmp->nm_wsize = NFS_MAXDATA;
+       }
+       if (nmp->nm_wsize > MAXBSIZE)
+               nmp->nm_wsize = MAXBSIZE;
+
+       if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
+               nmp->nm_rsize = argp->rsize;
+               /* Round down to multiple of blocksize */
+               nmp->nm_rsize &= ~0x1ff;
+               if (nmp->nm_rsize <= 0)
+                       nmp->nm_rsize = 512;
+               else if (nmp->nm_rsize > NFS_MAXDATA)
+                       nmp->nm_rsize = NFS_MAXDATA;
+       }
+       if (nmp->nm_rsize > MAXBSIZE)
+               nmp->nm_rsize = MAXBSIZE;
+       /* Set up the sockets and per-host congestion */
+       nmp->nm_sotype = argp->sotype;
+       nmp->nm_soproto = argp->proto;
+       if (error = nfs_connect(nmp))
+               goto bad;
+
+       if (error = nfs_statfs(mp, &mp->mnt_stat, p))
+               goto bad;
+       /*
+        * A reference count is needed on the nfsnode representing the
+        * remote root.  If this object is not persistent, then backward
+        * traversals of the mount point (i.e. "..") will not work if
+        * the nfsnode gets flushed out of the cache. Ufs does not have
+        * this problem, because one can identify root inodes by their
+        * number == ROOTINO (2).
+        */
+       if (error = nfs_nget(mp, &nmp->nm_fh, &np))
+               goto bad;
+       /*
+        * Unlock it, but keep the reference count.
+        */
+       nfs_unlock(NFSTOV(np));
+       *vpp = NFSTOV(np);
+
+       return (0);
+bad:
+       nfs_disconnect(nmp);
+       FREE(nmp, M_NFSMNT);
+       m_freem(nam);
+       return (error);
+}
+
+/*
+ * unmount system call
+ */
+nfs_unmount(mp, mntflags, p)
+       struct mount *mp;
+       int mntflags;
+       struct proc *p;
+{
+       register struct nfsmount *nmp;
+       struct nfsnode *np;
+       struct vnode *vp;
+       int error, flags = 0;
+       extern int doforce;
+
+       if (mntflags & MNT_FORCE) {
+               if (!doforce || mp == rootfs)
+                       return (EINVAL);
+               flags |= FORCECLOSE;
+       }
+       nmp = VFSTONFS(mp);
+       /*
+        * Clear out the buffer cache
+        */
+       mntflushbuf(mp, 0);
+       if (mntinvalbuf(mp))
+               return (EBUSY);
+       /*
+        * Goes something like this..
+        * - Check for activity on the root vnode (other than ourselves).
+        * - Call vflush() to clear out vnodes for this file system,
+        *   except for the root vnode.
+        * - Decrement reference on the vnode representing remote root.
+        * - Close the socket
+        * - Free up the data structures
+        */
+       /*
+        * We need to decrement the ref. count on the nfsnode representing
+        * the remote root.  See comment in mountnfs().  The VFS unmount()
+        * has done vput on this vnode, otherwise we would get deadlock!
+        */
+       if (error = nfs_nget(mp, &nmp->nm_fh, &np))
+               return(error);
+       vp = NFSTOV(np);
+       if (vp->v_usecount > 2) {
+               vput(vp);
+               return (EBUSY);
+       }
+       if (error = vflush(mp, vp, flags)) {
+               vput(vp);
+               return (error);
+       }
+       /*
+        * Get rid of two reference counts, and unlock it on the second.
+        */
+       vrele(vp);
+       vput(vp);
+       nfs_disconnect(nmp);
+       m_freem(nmp->nm_nam);
+       free((caddr_t)nmp, M_NFSMNT);
+       return (0);
+}
+
+/*
+ * Return root of a filesystem
+ */
+nfs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
+{
+       register struct vnode *vp;
+       struct nfsmount *nmp;
+       struct nfsnode *np;
+       int error;
+
+       nmp = VFSTONFS(mp);
+       if (error = nfs_nget(mp, &nmp->nm_fh, &np))
+               return (error);
+       vp = NFSTOV(np);
+       vp->v_type = VDIR;
+       vp->v_flag = VROOT;
+       *vpp = vp;
+       return (0);
+}
+
+extern int syncprt;
+
+/*
+ * Flush out the buffer cache
+ */
+/* ARGSUSED */
+nfs_sync(mp, waitfor)
+       struct mount *mp;
+       int waitfor;
+{
+       if (syncprt)
+               bufstats();
+       /*
+        * Force stale buffer cache information to be flushed.
+        */
+       mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
+       return (0);
+}
+
+/*
+ * At this point, this should never happen
+ */
+/* ARGSUSED */
+nfs_fhtovp(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen either
+ */
+/* ARGSUSED */
+nfs_vptofh(vp, fhp)
+       struct vnode *vp;
+       struct fid *fhp;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Vfs start routine, a no-op.
+ */
+/* ARGSUSED */
+nfs_start(mp, flags, p)
+       struct mount *mp;
+       int flags;
+       struct proc *p;
+{
+
+       return (0);
+}
+
+/*
+ * Do operations associated with quotas, not supported
+ */
+nfs_quotactl(mp, cmd, uid, arg, p)
+       struct mount *mp;
+       int cmd;
+       uid_t uid;
+       caddr_t arg;
+       struct proc *p;
+{
+#ifdef lint
+       mp = mp; cmd = cmd; uid = uid; arg = arg;
+#endif /* lint */
+       return (EOPNOTSUPP);
+}
diff --git a/usr/src/sys.386bsd/nfs/nfscompress.h b/usr/src/sys.386bsd/nfs/nfscompress.h
new file mode 100644 (file)
index 0000000..fed621c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfscompress.h       7.2 (Berkeley) 10/2/90
+ */
+
+/*
+ * Definitions for the compression algorithm
+ */
+#define NFSC_MAX       17
+#define        NFSCRL          0xe0
+#define        NFSCRLE(a)      (NFSCRL | ((a) - 2))
+
+#define        nfscput(c) \
+               if (oleft == 0) { \
+                       MGET(om, M_WAIT, MT_DATA); \
+                       if (clget) \
+                               MCLGET(om, M_WAIT); \
+                       om->m_len = 0; \
+                       oleft = M_TRAILINGSPACE(om) - 1; \
+                       *mp = om; \
+                       mp = &om->m_next; \
+                       op = mtod(om, u_char *); \
+               } else \
+                       oleft--; \
+               *op++ = (c); \
+               om->m_len++; \
+               olen++
+
+#define nfscget(c) \
+               if (ileft == 0) { \
+                       do { \
+                               m = m->m_next; \
+                       } while (m && m->m_len == 0); \
+                       if (m) { \
+                               ileft = m->m_len - 1; \
+                               ip = mtod(m, u_char *); \
+                               (c) = *ip++; \
+                       } else { \
+                               (c) = '\0'; \
+                               noteof = 0; \
+                       } \
+               } else { \
+                       (c) = *ip++; \
+                       ileft--; \
+               }
diff --git a/usr/src/sys.386bsd/nfs/nfsdiskless.h b/usr/src/sys.386bsd/nfs/nfsdiskless.h
new file mode 100644 (file)
index 0000000..bee5d12
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsdiskless.h       7.1 (Berkeley) 3/4/91
+ */
+
+/*
+ * Structure that must be initialized for a diskless nfs client.
+ * This structure is used by nfs_mountroot() to set up the root and swap
+ * vnodes plus do a partial ifconfig(8) and route(8) so that the critical net
+ * interface can communicate with the server.
+ * For now it is statically initialized in swapvmunix.c, but someday a primary
+ * bootstrap should fill it in.
+ */
+struct nfs_diskless {
+       struct ifaliasreq myif;         /* Info. for partial ifconfig */
+       struct sockaddr mygateway;      /* Default gateway for "route add" */
+       struct nfs_args swap_args;      /* Mount args for swap file */
+       u_char          swap_fh[NFS_FHSIZE]; /* Swap file's file handle */
+       struct sockaddr swap_saddr;     /* Address of swap server */
+       char            *swap_hostnam;  /* Host name for mount pt */
+       struct nfs_args root_args;      /* Mount args for root fs */
+       u_char          root_fh[NFS_FHSIZE]; /* File handle of root dir */
+       struct sockaddr root_saddr;     /* Address of root server */
+       char            *root_hostnam;  /* Host name for mount pt */
+};
diff --git a/usr/src/sys.386bsd/nfs/nfsiom.h b/usr/src/sys.386bsd/nfs/nfsiom.h
new file mode 100644 (file)
index 0000000..0466b7a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsiom.h    7.3 (Berkeley) 6/28/90
+ */
+
+/*
+ * Size of the resource map and system page table pte's that are mapped
+ * by nfs for i/o much like a bus adapter
+ */
+#define        NFS_MAPREG      512     /* Num. of kernel pte's for i/o mapping */
+                               /* Must be >= MAXPHYS/NBPG */
+#define        NFS_MSIZ        100     /* Size of alloc. map for pte's */
diff --git a/usr/src/sys.386bsd/nfs/nfsm_subs.h b/usr/src/sys.386bsd/nfs/nfsm_subs.h
new file mode 100644 (file)
index 0000000..7bbf77c
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsm_subs.h 7.11 (Berkeley) 4/16/91
+ */
+
+/*
+ * These macros do strange and peculiar things to mbuf chains for
+ * the assistance of the nfs code. To attempt to use them for any
+ * other purpose will be dangerous. (they make weird assumptions)
+ */
+
+/*
+ * First define what the actual subs. return
+ */
+extern struct mbuf *nfsm_reqh();
+
+#define        M_HASCL(m)      ((m)->m_flags & M_EXT)
+#define        NFSMGETHDR(m) \
+               MGETHDR(m, M_WAIT, MT_DATA); \
+               (m)->m_pkthdr.len = 0; \
+               (m)->m_pkthdr.rcvif = (struct ifnet *)0
+#define        NFSMINOFF(m) \
+               if (M_HASCL(m)) \
+                       (m)->m_data = (m)->m_ext.ext_buf; \
+               else \
+                       (m)->m_data = (m)->m_dat
+#define        NFSMADV(m, s)   (m)->m_data += (s)
+#define        NFSMSIZ(m)      ((M_HASCL(m))?MCLBYTES: \
+                               (((m)->m_flags & M_PKTHDR)?MHLEN:MLEN))
+
+/*
+ * Now for the macros that do the simple stuff and call the functions
+ * for the hard stuff.
+ * These macros use several vars. declared in nfsm_reqhead and these
+ * vars. must not be used elsewhere unless you are careful not to corrupt
+ * them. The vars. starting with pN and tN (N=1,2,3,..) are temporaries
+ * that may be used so long as the value is not expected to retained
+ * after a macro.
+ * I know, this is kind of dorkey, but it makes the actual op functions
+ * fairly clean and deals with the mess caused by the xdr discriminating
+ * unions.
+ */
+
+#ifndef lint
+#define        nfsm_build(a,c,s) \
+               t1 = NFSMSIZ(mb); \
+               if ((s) > (t1-mb->m_len)) { \
+                       MGET(mb2, M_WAIT, MT_DATA); \
+                       if ((s) > MLEN) \
+                               panic("build > MLEN"); \
+                       mb->m_next = mb2; \
+                       mb = mb2; \
+                       mb->m_len = 0; \
+                       bpos = mtod(mb, caddr_t); \
+               } \
+               (a) = (c)(bpos); \
+               mb->m_len += (s); \
+               bpos += (s)
+#else /* lint */
+#define        nfsm_build(a,c,s) \
+               t1 = NFSMSIZ(mb); \
+               if ((s) > (t1-mb->m_len)) { \
+                       MGET(mb2, M_WAIT, MT_DATA); \
+                       mb->m_next = mb2; \
+                       mb = mb2; \
+                       mb->m_len = 0; \
+                       bpos = mtod(mb, caddr_t); \
+               } \
+               (a) = (c)(bpos); \
+               mb->m_len += (s); \
+               bpos += (s)
+#endif /* lint */
+
+#define        nfsm_disect(a,c,s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+               if (t1 >= (s)) { \
+                       (a) = (c)(dpos); \
+                       dpos += (s); \
+               } else if (error = nfsm_disct(&md, &dpos, (s), t1, TRUE, &cp2)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               } else { \
+                       (a) = (c)cp2; \
+               }
+
+#define        nfsm_disecton(a,c,s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+               if (t1 >= (s)) { \
+                       (a) = (c)(dpos); \
+                       dpos += (s); \
+               } else if (error = nfsm_disct(&md, &dpos, (s), t1, FALSE, &cp2)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               } else { \
+                       (a) = (c)cp2; \
+               }
+
+#define nfsm_fhtom(v) \
+               nfsm_build(cp,caddr_t,NFSX_FH); \
+               bcopy((caddr_t)&(VTONFS(v)->n_fh), cp, NFSX_FH)
+
+#define nfsm_srvfhtom(f) \
+               nfsm_build(cp,caddr_t,NFSX_FH); \
+               bcopy((caddr_t)(f), cp, NFSX_FH)
+
+#define nfsm_mtofh(d,v) \
+               { struct nfsnode *np; nfsv2fh_t *fhp; \
+               nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); \
+               if (error = nfs_nget((d)->v_mount, fhp, &np)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               } \
+               (v) = NFSTOV(np); \
+               nfsm_loadattr(v, (struct vattr *)0); \
+               }
+
+#define        nfsm_loadattr(v,a) \
+               { struct vnode *tvp = (v); \
+               if (error = nfs_loadattrcache(&tvp, &md, &dpos, (a))) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               } \
+               (v) = tvp; }
+
+#define        nfsm_strsiz(s,m) \
+               nfsm_disect(tl,u_long *,NFSX_UNSIGNED); \
+               if (((s) = fxdr_unsigned(long,*tl)) > (m)) { \
+                       m_freem(mrep); \
+                       error = EBADRPC; \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_srvstrsiz(s,m) \
+               nfsm_disect(tl,u_long *,NFSX_UNSIGNED); \
+               if (((s) = fxdr_unsigned(long,*tl)) > (m) || (s) <= 0) { \
+                       error = EBADRPC; \
+                       nfsm_reply(0); \
+               }
+
+#define nfsm_mtouio(p,s) \
+               if ((s) > 0 && \
+                  (error = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               }
+
+#define nfsm_uiotom(p,s) \
+               if (error = nfsm_uiotombuf((p),&mb,(s),&bpos)) { \
+                       m_freem(mreq); \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_reqhead(a,c,s) \
+               if ((mreq = nfsm_reqh(nfs_prog,nfs_vers,(a),(c),(s),&bpos,&mb,&xid)) == NULL) { \
+                       error = ENOBUFS; \
+                       goto nfsmout; \
+               }
+
+#define nfsm_reqdone   m_freem(mrep); \
+               nfsmout: 
+
+#define nfsm_rndup(a)  (((a)+3)&(~0x3))
+
+#define        nfsm_request(v, t, p, h)        \
+               if (error = nfs_request((v), mreq, xid, (t), (p), (h), \
+                  (v)->v_mount, &mrep, &md, &dpos)) \
+                       goto nfsmout
+
+#define        nfsm_strtom(a,s,m) \
+               if ((s) > (m)) { \
+                       m_freem(mreq); \
+                       error = ENAMETOOLONG; \
+                       goto nfsmout; \
+               } \
+               t2 = nfsm_rndup(s)+NFSX_UNSIGNED; \
+               if(t2<=(NFSMSIZ(mb)-mb->m_len)){ \
+                       nfsm_build(tl,u_long *,t2); \
+                       *tl++ = txdr_unsigned(s); \
+                       *(tl+((t2>>2)-2)) = 0; \
+                       bcopy((caddr_t)(a), (caddr_t)tl, (s)); \
+               } else if (error = nfsm_strtmbuf(&mb, &bpos, (a), (s))) { \
+                       m_freem(mreq); \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_srvdone \
+               nfsmout: \
+               return(error)
+
+#ifndef lint
+#define        nfsm_reply(s) \
+               { \
+               *repstat = error; \
+               if (error) \
+                       nfs_rephead(0, xid, error, mrq, &mb, &bpos); \
+               else \
+                       nfs_rephead((s), xid, error, mrq, &mb, &bpos); \
+               m_freem(mrep); \
+               mreq = *mrq; \
+               if (error) \
+                       return(0); \
+               }
+#else  /* lint */
+#define        nfsm_reply(s) \
+               { \
+               *repstat = error; \
+               if (error) \
+                       nfs_rephead(0, xid, error, mrq, &mb, &bpos); \
+               else \
+                       nfs_rephead((s), xid, error, mrq, &mb, &bpos); \
+               m_freem(mrep); \
+               mreq = *mrq; \
+               mrep = mreq; \
+               if (error) \
+                       return(0); \
+               }
+#endif /* lint */
+
+#define        nfsm_adv(s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+               if (t1 >= (s)) { \
+                       dpos += (s); \
+               } else if (error = nfs_adv(&md, &dpos, (s), t1)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               }
+
+#define nfsm_srvmtofh(f) \
+               nfsm_disecton(tl, u_long *, NFSX_FH); \
+               bcopy((caddr_t)tl, (caddr_t)f, NFSX_FH)
+
+#define        nfsm_clget \
+               if (bp >= be) { \
+                       MGET(mp, M_WAIT, MT_DATA); \
+                       MCLGET(mp, M_WAIT); \
+                       mp->m_len = NFSMSIZ(mp); \
+                       if (mp3 == NULL) \
+                               mp3 = mp2 = mp; \
+                       else { \
+                               mp2->m_next = mp; \
+                               mp2 = mp; \
+                       } \
+                       bp = mtod(mp, caddr_t); \
+                       be = bp+mp->m_len; \
+               } \
+               tl = (u_long *)bp
+
+#define        nfsm_srvfillattr \
+       fp->fa_type = vtonfs_type(vap->va_type); \
+       fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode); \
+       fp->fa_nlink = txdr_unsigned(vap->va_nlink); \
+       fp->fa_uid = txdr_unsigned(vap->va_uid); \
+       fp->fa_gid = txdr_unsigned(vap->va_gid); \
+       fp->fa_size = txdr_unsigned(vap->va_size); \
+       fp->fa_blocksize = txdr_unsigned(vap->va_blocksize); \
+       if (vap->va_type == VFIFO) \
+               fp->fa_rdev = 0xffffffff; \
+       else \
+               fp->fa_rdev = txdr_unsigned(vap->va_rdev); \
+       fp->fa_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); \
+       fp->fa_fsid = txdr_unsigned(vap->va_fsid); \
+       fp->fa_fileid = txdr_unsigned(vap->va_fileid); \
+       fp->fa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec); \
+       fp->fa_atime.tv_usec = txdr_unsigned(vap->va_flags); \
+       txdr_time(&vap->va_mtime, &fp->fa_mtime); \
+       fp->fa_ctime.tv_sec = txdr_unsigned(vap->va_ctime.tv_sec); \
+       fp->fa_ctime.tv_usec = txdr_unsigned(vap->va_gen)
+
diff --git a/usr/src/sys.386bsd/nfs/nfsmount.h b/usr/src/sys.386bsd/nfs/nfsmount.h
new file mode 100644 (file)
index 0000000..a2a2c5d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsmount.h  7.7 (Berkeley) 4/16/91
+ */
+
+/*
+ * Mount structure.
+ * One allocated on every NFS mount.
+ * Holds NFS specific information for mount.
+ */
+struct nfsmount {
+       int     nm_flag;                /* Flags for soft/hard... */
+       struct  mount *nm_mountp;       /* Vfs structure for this filesystem */
+       nfsv2fh_t nm_fh;                /* File handle of root dir */
+       struct  socket *nm_so;          /* Rpc socket */
+       int     nm_sotype;              /* Type of socket */
+       int     nm_soproto;             /* and protocol */
+       int     nm_soflags;             /* pr_flags for socket protocol */
+       struct  mbuf *nm_nam;           /* Addr of server */
+       short   nm_retry;               /* Max retry count */
+       short   nm_rexmit;              /* Rexmit on previous request */
+       short   nm_rtt;                 /* Round trip timer ticks @ NFS_HZ */
+       short   nm_rto;                 /* Current timeout */
+       short   nm_srtt;                /* Smoothed round trip time */
+       short   nm_rttvar;              /* RTT variance */
+       short   nm_currto;              /* Current rto of any nfsmount */
+       short   nm_currexmit;           /* Max rexmit count of nfsmounts */
+       short   nm_sent;                /* Request send count */
+       short   nm_window;              /* Request send window (max) */
+       short   nm_winext;              /* Window incremental value */
+       short   nm_ssthresh;            /* Slowstart threshold */
+       short   nm_salen;               /* Actual length of nm_sockaddr */
+       int     nm_rsize;               /* Max size of read rpc */
+       int     nm_wsize;               /* Max size of write rpc */
+};
+
+#ifdef KERNEL
+/*
+ * Convert mount ptr to nfsmount ptr.
+ */
+#define VFSTONFS(mp)   ((struct nfsmount *)((mp)->mnt_data))
+#endif /* KERNEL */
+
+/*
+ * Prototypes for NFS mount operations
+ */
+int    nfs_mount __P((
+               struct mount *mp,
+               char *path,
+               caddr_t data,
+               struct nameidata *ndp,
+               struct proc *p));
+int    nfs_start __P((
+               struct mount *mp,
+               int flags,
+               struct proc *p));
+int    nfs_unmount __P((
+               struct mount *mp,
+               int mntflags,
+               struct proc *p));
+int    nfs_root __P((
+               struct mount *mp,
+               struct vnode **vpp));
+int    nfs_quotactl __P((
+               struct mount *mp,
+               int cmds,
+               int uid,        /* should be uid_t */
+               caddr_t arg,
+               struct proc *p));
+int    nfs_statfs __P((
+               struct mount *mp,
+               struct statfs *sbp,
+               struct proc *p));
+int    nfs_sync __P((
+               struct mount *mp,
+               int waitfor));
+int    nfs_fhtovp __P((
+               struct mount *mp,
+               struct fid *fhp,
+               struct vnode **vpp));
+int    nfs_vptofh __P((
+               struct vnode *vp,
+               struct fid *fhp));
+int    nfs_init __P(());
diff --git a/usr/src/sys.386bsd/nfs/nfsnode.h b/usr/src/sys.386bsd/nfs/nfsnode.h
new file mode 100644 (file)
index 0000000..e08a338
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsnode.h   7.12 (Berkeley) 4/16/91
+ */
+
+/*
+ * The nfsnode is the nfs equivalent to ufs's inode. Any similarity
+ * is purely coincidental.
+ * There is a unique nfsnode allocated for each active file,
+ * each current directory, each mounted-on file, text file, and the root.
+ * An nfsnode is 'named' by its file handle. (nget/nfs_node.c)
+ */
+
+struct nfsnode {
+       struct  nfsnode *n_chain[2];    /* must be first */
+       nfsv2fh_t n_fh;                 /* NFS File Handle */
+       long    n_flag;                 /* Flag for locking.. */
+       struct  vnode *n_vnode; /* vnode associated with this nfsnode */
+       time_t  n_attrstamp;    /* Time stamp (sec) for attributes */
+       struct  vattr n_vattr;  /* Vnode attribute cache */
+       struct  sillyrename *n_sillyrename;     /* Ptr to silly rename struct */
+       u_long  n_size;         /* Current size of file */
+       time_t  n_mtime;        /* Prev modify time to maintain data cache consistency*/
+       time_t  n_ctime;        /* Prev create time for name cache consistency*/
+       int     n_error;        /* Save write error value */
+       pid_t   n_lockholder;   /* holder of nfsnode lock */
+       pid_t   n_lockwaiter;   /* most recent waiter for nfsnode lock */
+       u_long  n_direofoffset; /* Dir. EOF offset cache */
+};
+
+#define        n_forw          n_chain[0]
+#define        n_back          n_chain[1]
+
+#ifdef KERNEL
+/*
+ * Convert between nfsnode pointers and vnode pointers
+ */
+#define VTONFS(vp)     ((struct nfsnode *)(vp)->v_data)
+#define NFSTOV(np)     ((struct vnode *)(np)->n_vnode)
+#endif
+/*
+ * Flags for n_flag
+ */
+#define        NLOCKED         0x1     /* Lock the node for other local accesses */
+#define        NWANT           0x2     /* Want above lock */
+#define        NMODIFIED       0x4     /* Might have a modified buffer in bio */
+#define        NWRITEERR       0x8     /* Flag write errors so close will know */
+
+/*
+ * Prototypes for NFS vnode operations
+ */
+int    nfs_lookup __P((
+               struct vnode *vp,
+               struct nameidata *ndp,
+               struct proc *p));
+int    nfs_create __P((
+               struct nameidata *ndp,
+               struct vattr *vap,
+               struct proc *p));
+int    nfs_mknod __P((
+               struct nameidata *ndp,
+               struct vattr *vap,
+               struct ucred *cred,
+               struct proc *p));
+int    nfs_open __P((
+               struct vnode *vp,
+               int mode,
+               struct ucred *cred,
+               struct proc *p));
+int    nfs_close __P((
+               struct vnode *vp,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+int    nfs_access __P((
+               struct vnode *vp,
+               int mode,
+               struct ucred *cred,
+               struct proc *p));
+int    nfs_getattr __P((
+               struct vnode *vp,
+               struct vattr *vap,
+               struct ucred *cred,
+               struct proc *p));
+int    nfs_setattr __P((
+               struct vnode *vp,
+               struct vattr *vap,
+               struct ucred *cred,
+               struct proc *p));
+int    nfs_read __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+int    nfs_write __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+#define nfs_ioctl ((int (*) __P(( \
+               struct vnode *vp, \
+               int command, \
+               caddr_t data, \
+               int fflag, \
+               struct ucred *cred, \
+               struct proc *p))) enoioctl)
+#define nfs_select ((int (*) __P(( \
+               struct vnode *vp, \
+               int which, \
+               int fflags, \
+               struct ucred *cred, \
+               struct proc *p))) seltrue)
+int    nfs_mmap __P((
+               struct vnode *vp,
+               int fflags,
+               struct ucred *cred,
+               struct proc *p));
+int    nfs_fsync __P((
+               struct vnode *vp,
+               int fflags,
+               struct ucred *cred,
+               int waitfor,
+               struct proc *p));
+#define nfs_seek ((int (*) __P(( \
+               struct vnode *vp, \
+               off_t oldoff, \
+               off_t newoff, \
+               struct ucred *cred))) nullop)
+int    nfs_remove __P((
+               struct nameidata *ndp,
+               struct proc *p));
+int    nfs_link __P((
+               struct vnode *vp,
+               struct nameidata *ndp,
+               struct proc *p));
+int    nfs_rename __P((
+               struct nameidata *fndp,
+               struct nameidata *tdnp,
+               struct proc *p));
+int    nfs_mkdir __P((
+               struct nameidata *ndp,
+               struct vattr *vap,
+               struct proc *p));
+int    nfs_rmdir __P((
+               struct nameidata *ndp,
+               struct proc *p));
+int    nfs_symlink __P((
+               struct nameidata *ndp,
+               struct vattr *vap,
+               char *target,
+               struct proc *p));
+int    nfs_readdir __P((
+               struct vnode *vp,
+               struct uio *uio,
+               struct ucred *cred,
+               int *eofflagp));
+int    nfs_readlink __P((
+               struct vnode *vp,
+               struct uio *uio,
+               struct ucred *cred));
+int    nfs_abortop __P((
+               struct nameidata *ndp));
+int    nfs_inactive __P((
+               struct vnode *vp,
+               struct proc *p));
+int    nfs_reclaim __P((
+               struct vnode *vp));
+int    nfs_lock __P((
+               struct vnode *vp));
+int    nfs_unlock __P((
+               struct vnode *vp));
+int    nfs_bmap __P((
+               struct vnode *vp,
+               daddr_t bn,
+               struct vnode **vpp,
+               daddr_t *bnp));
+int    nfs_strategy __P((
+               struct buf *bp));
+int    nfs_print __P((
+               struct vnode *vp));
+int    nfs_islocked __P((
+               struct vnode *vp));
+int    nfs_advlock __P((
+               struct vnode *vp,
+               caddr_t id,
+               int op,
+               struct flock *fl,
+               int flags));
diff --git a/usr/src/sys.386bsd/nfs/nfsrvcache.h b/usr/src/sys.386bsd/nfs/nfsrvcache.h
new file mode 100644 (file)
index 0000000..7aa6f81
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsrvcache.h        7.3 (Berkeley) 6/28/90
+ */
+
+/*
+ * Definitions for the server recent request cache
+ */
+
+#define        NFSRVCACHESIZ   128
+#define        NFSRCHSZ        32
+
+struct nfsrvcache {
+       struct  nfsrvcache *rc_chain[2];        /* Hash chain links */
+       struct  nfsrvcache *rc_next;    /* Lru list */
+       struct  nfsrvcache *rc_prev;
+       int     rc_state;               /* Current state of request */
+       int     rc_flag;                /* Flag bits */
+       struct  mbuf rc_nam;            /* Sockaddr of requestor */
+       u_long  rc_xid;                 /* rpc id number */
+       int     rc_proc;                /* rpc proc number */
+       long    rc_timestamp;           /* Time stamp */
+       union {
+               struct mbuf *rc_repmb;  /* Reply mbuf list OR */
+               int rc_repstat;         /* Reply status */
+       } rc_un;
+};
+
+#define        rc_forw         rc_chain[0]
+#define        rc_back         rc_chain[1]
+#define        rc_status       rc_un.rc_repstat
+#define        rc_reply        rc_un.rc_repmb
+
+#define        put_at_head(rp) \
+               (rp)->rc_prev->rc_next = (rp)->rc_next; \
+               (rp)->rc_next->rc_prev = (rp)->rc_prev; \
+               (rp)->rc_next = nfsrvcachehead.rc_next; \
+               (rp)->rc_next->rc_prev = (rp); \
+               nfsrvcachehead.rc_next = (rp); \
+               (rp)->rc_prev = &nfsrvcachehead
+
+/* Cache entry states */
+#define        RC_UNUSED       0
+#define        RC_INPROG       1
+#define        RC_DONE         2
+
+/* Return values */
+#define        RC_DROPIT       0
+#define        RC_REPLY        1
+#define        RC_DOIT         2
+
+/* Flag bits */
+#define        RC_LOCKED       0x1
+#define        RC_WANTED       0x2
+#define        RC_REPSTATUS    0x4
+#define        RC_REPMBUF      0x8
+
+/* Delay time after completion that request is dropped */
+#define        RC_DELAY        2               /* seconds */
+
diff --git a/usr/src/sys.386bsd/nfs/nfsv2.h b/usr/src/sys.386bsd/nfs/nfsv2.h
new file mode 100644 (file)
index 0000000..ae46687
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)nfsv2.h     7.8 (Berkeley) 6/28/90
+ */
+
+/*
+ * nfs definitions as per the version 2 specs
+ */
+
+/*
+ * Constants as defined in the Sun NFS Version 2 spec.
+ * "NFS: Network File System Protocol Specification" RFC1094
+ */
+
+#define NFS_PORT       2049
+#define        NFS_PROG        100003
+#define NFS_VER2       2
+#define        NFS_MAXDGRAMDATA 8192
+#define        NFS_MAXDATA     32768
+#define        NFS_MAXPATHLEN  1024
+#define        NFS_MAXNAMLEN   255
+#define        NFS_FHSIZE      32
+#define        NFS_MAXPKTHDR   404
+#define NFS_MAXPACKET  (NFS_MAXPKTHDR+NFS_MAXDATA)
+#define        NFS_NPROCS      18
+#define        NFS_FABLKSIZE   512     /* Size in bytes of a block wrt fa_blocks */
+
+/* Stat numbers for rpc returns */
+#define        NFS_OK          0
+#define        NFSERR_PERM     1
+#define        NFSERR_NOENT    2
+#define        NFSERR_IO       5
+#define        NFSERR_NXIO     6
+#define        NFSERR_ACCES    13
+#define        NFSERR_EXIST    17
+#define        NFSERR_NODEV    19
+#define        NFSERR_NOTDIR   20
+#define        NFSERR_ISDIR    21
+#define        NFSERR_FBIG     27
+#define        NFSERR_NOSPC    28
+#define        NFSERR_ROFS     30
+#define        NFSERR_NAMETOOLONG      63
+#define        NFSERR_NOTEMPTY 66
+#define        NFSERR_DQUOT    69
+#define        NFSERR_STALE    70
+#define        NFSERR_WFLUSH   99
+
+/* Sizes in bytes of various nfs rpc components */
+#define        NFSX_FH         32
+#define        NFSX_UNSIGNED   4
+#define        NFSX_FATTR      68
+#define        NFSX_SATTR      32
+#define        NFSX_COOKIE     4
+#define NFSX_STATFS    20
+
+/* nfs rpc procedure numbers */
+#define        NFSPROC_NULL            0
+#define        NFSPROC_GETATTR         1
+#define        NFSPROC_SETATTR         2
+#define        NFSPROC_ROOT            3               /* Obsolete */
+#define        NFSPROC_LOOKUP          4
+#define        NFSPROC_READLINK        5
+#define        NFSPROC_READ            6
+#define        NFSPROC_WRITECACHE      7               /* Obsolete */
+#define        NFSPROC_WRITE           8
+#define        NFSPROC_CREATE          9
+#define        NFSPROC_REMOVE          10
+#define        NFSPROC_RENAME          11
+#define        NFSPROC_LINK            12
+#define        NFSPROC_SYMLINK         13
+#define        NFSPROC_MKDIR           14
+#define        NFSPROC_RMDIR           15
+#define        NFSPROC_READDIR         16
+#define        NFSPROC_STATFS          17
+
+/* Conversion macros */
+extern int             vttoif_tab[];
+#define        vtonfs_mode(t,m) \
+               txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \
+                               MAKEIMODE((t), (m)))
+#define        nfstov_mode(a)  (fxdr_unsigned(u_short, (a))&07777)
+#define        vtonfs_type(a)  txdr_unsigned(nfs_type[((long)(a))])
+#define        nfstov_type(a)  ntov_type[fxdr_unsigned(u_long,(a))&0x7]
+
+/* File types */
+typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 } nfstype;
+
+/* Structs for common parts of the rpc's */
+struct nfsv2_time {
+       u_long  tv_sec;
+       u_long  tv_usec;
+};
+
+struct nfsv2_fattr {
+       u_long  fa_type;
+       u_long  fa_mode;
+       u_long  fa_nlink;
+       u_long  fa_uid;
+       u_long  fa_gid;
+       u_long  fa_size;
+       u_long  fa_blocksize;
+       u_long  fa_rdev;
+       u_long  fa_blocks;
+       u_long  fa_fsid;
+       u_long  fa_fileid;
+       struct nfsv2_time fa_atime;
+       struct nfsv2_time fa_mtime;
+       struct nfsv2_time fa_ctime;
+};
+
+struct nfsv2_sattr {
+       u_long  sa_mode;
+       u_long  sa_uid;
+       u_long  sa_gid;
+       u_long  sa_size;
+       struct nfsv2_time sa_atime;
+       struct nfsv2_time sa_mtime;
+};
+
+struct nfsv2_statfs {
+       u_long  sf_tsize;
+       u_long  sf_bsize;
+       u_long  sf_blocks;
+       u_long  sf_bfree;
+       u_long  sf_bavail;
+};
diff --git a/usr/src/sys.386bsd/nfs/rpcv2.h b/usr/src/sys.386bsd/nfs/rpcv2.h
new file mode 100644 (file)
index 0000000..8f81484
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)rpcv2.h     7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Definitions for Sun RPC Version 2, from
+ * "RPC: Remote Procedure Call Protocol Specification" RFC1057
+ */
+
+/* Version # */
+#define        RPC_VER2        2
+
+/* Authentication */
+#define        RPCAUTH_NULL    0
+#define        RPCAUTH_UNIX    1
+#define        RPCAUTH_SHORT   2
+#define        RPCAUTH_MAXSIZ  400
+#define        RPCAUTH_UNIXGIDS 16
+
+/* Rpc Constants */
+#define        RPC_CALL        0
+#define        RPC_REPLY       1
+#define        RPC_MSGACCEPTED 0
+#define        RPC_MSGDENIED   1
+#define        RPC_PROGUNAVAIL 1
+#define        RPC_PROGMISMATCH        2
+#define        RPC_PROCUNAVAIL 3
+#define        RPC_GARBAGE     4               /* I like this one */
+#define        RPC_MISMATCH    0
+#define        RPC_AUTHFAIL    1
+
+/* Authentication failures */
+#define        AUTH_BADCRED    1
+#define        AUTH_REJECTCRED 2
+#define        AUTH_BADVERF    3
+#define        AUTH_REJECTVERF 4
+#define        AUTH_TOOWEAK    5               /* Give em wheaties */
+
+/* Sizes of rpc header parts */
+#define        RPC_SIZ         24
+#define        RPC_REPLYSIZ    28
+
+/* RPC Prog definitions */
+#define        RPCPROG_MNT     100005
+#define        RPCMNT_VER1     1
+#define        RPCMNT_MOUNT    1
+#define        RPCMNT_DUMP     2
+#define        RPCMNT_UMOUNT   3
+#define        RPCMNT_UMNTALL  4
+#define        RPCMNT_EXPORT   5
+#define        RPCMNT_NAMELEN  255
+#define        RPCMNT_PATHLEN  1024
+#define        RPCPROG_NFS     100003
diff --git a/usr/src/sys.386bsd/nfs/xdr_subs.h b/usr/src/sys.386bsd/nfs/xdr_subs.h
new file mode 100644 (file)
index 0000000..5bf212d
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)xdr_subs.h  7.3 (Berkeley) 6/28/90
+ */
+
+/*
+ * Macros used for conversion to/from xdr representation by nfs...
+ * These use the MACHINE DEPENDENT routines ntohl, htonl
+ * As defined by "XDR: External Data Representation Standard" RFC1014
+ */
+/* From xdr to machine */
+#define fxdr_unsigned(t, v)    ((t)ntohl((long)(v)))
+#define        fxdr_time(f, t)         {((struct timeval *)(t))->tv_sec=ntohl( \
+                               ((struct timeval *)(f))->tv_sec); \
+                               ((struct timeval *)(t))->tv_usec=ntohl( \
+                               ((struct timeval *)(f))->tv_usec);}
+
+/* from machine to xdr */
+#define        txdr_unsigned(v)        (htonl((long)(v)))
+#define        txdr_time(f, t)         {((struct timeval *)(t))->tv_sec=htonl( \
+                               ((struct timeval *)(f))->tv_sec); \
+                               ((struct timeval *)(t))->tv_usec=htonl( \
+                               ((struct timeval *)(f))->tv_usec);}
+
diff --git a/usr/src/sys.386bsd/stand/cat.c b/usr/src/sys.386bsd/stand/cat.c
new file mode 100644 (file)
index 0000000..6f4067c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)cat.c       7.5 (Berkeley) 6/28/90
+ */
+
+main()
+{
+       register int c, fd;
+
+       fd = getfile("File", 0);
+       while ((c = getc(fd)) >= 0)
+               putchar(c);
+       exit(0);
+}
diff --git a/usr/src/sys.386bsd/stand/copy.c b/usr/src/sys.386bsd/stand/copy.c
new file mode 100644 (file)
index 0000000..b77d5e2
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 1982, 1986, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)copy.c      7.7 (Berkeley) 5/21/91
+ */
+
+#define        BSIZE   10240
+
+/*
+ * Copy from from to to.  Intended for use in system installation.
+ */
+main()
+{
+       extern int errno;
+       register int from, to, record, rcc, wcc, bsize = BSIZE;
+       char buf[BSIZE];
+
+       from = getfile("From", 0);
+       to = getfile("To", 1);
+       for (record = 0;; ++record) {
+               if (!(rcc = read(from, buf, bsize)))
+                       break;
+               if (rcc < 0) {
+                       printf("Record %d: read error, errno=%d\n",
+                           record, errno);
+                       break;
+               }
+               if (rcc != bsize) {
+                       if (record == 0) {
+                               bsize = rcc;
+                               printf("Block size set from input; %d bytes\n",
+                                   bsize);
+                       } else
+                               printf("Record %d: read short; expected %d, got %d\n",
+                                   record, bsize, rcc);
+               }
+#ifdef vax
+               /* For bug in ht driver. */
+               if (rcc > bsize)
+                       rcc = bsize;
+#endif
+               if ((wcc = write(to, buf, rcc)) < 0) {
+                       printf("Record %d: write error: errno=%d\n",
+                           record, errno);
+                       break;
+               }
+               if (wcc < rcc) {
+                       printf("Record %d: write short; expected %d, got %d\n",
+                           record, rcc, wcc);
+                       break;
+               }
+       }
+       printf("copy completed: %d records copied\n", record);
+}
diff --git a/usr/src/sys.386bsd/stand/dev.c b/usr/src/sys.386bsd/stand/dev.c
new file mode 100644 (file)
index 0000000..bfe3b05
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dev.c       7.14 (Berkeley) 5/5/91
+ */
+
+#include <sys/param.h>
+#include <setjmp.h>
+#include "saio.h"
+
+/*
+ * NB: the value "io->i_dev", used to offset the devsw[] array in the
+ * routines below, is munged by the machine specific stand Makefiles
+ * to work for certain boots.
+ */
+
+jmp_buf exception;
+
+devread(io)
+       register struct iob *io;
+{
+       int cc;
+
+       io->i_flgs |= F_RDDATA;
+       io->i_error = 0;
+       cc = (*devsw[io->i_dev].dv_strategy)(io, F_READ);
+       io->i_flgs &= ~F_TYPEMASK;
+#ifndef SMALL
+       if (scankbd())
+               _longjmp(exception, 1);
+#endif
+       return (cc);
+}
+
+devwrite(io)
+       register struct iob *io;
+{
+       int cc;
+
+       io->i_flgs |= F_WRDATA;
+       io->i_error = 0;
+       cc = (*devsw[io->i_dev].dv_strategy)(io, F_WRITE);
+       io->i_flgs &= ~F_TYPEMASK;
+#ifndef SMALL
+       if (scankbd())
+               _longjmp(exception, 1);
+#endif
+       return (cc);
+}
+
+devopen(io)
+       register struct iob *io;
+{
+       int ret;
+
+       if (!(ret = (*devsw[io->i_dev].dv_open)(io)))
+               return (0);
+#ifdef SMALL
+       printf("open error\n");
+#else
+       printf("%s(%d,%d,%d,%d): ", devsw[io->i_dev].dv_name,
+               io->i_adapt, io->i_ctlr, io->i_unit, io->i_part);
+       switch(ret) {
+       case EIO:
+               break;          /* already reported */
+       case EADAPT:
+               printf("bad adaptor number\n");
+               break;
+       case ECTLR:
+               printf("bad controller number\n");
+               break;
+       case EUNIT:
+               printf("bad drive number\n");
+               break;
+       case EPART:
+               printf("bad partition\n");
+               break;
+       case ERDLAB:
+               printf("can't read disk label\n");
+               break;
+       case EUNLAB:
+               printf("unlabeled\n");
+               break;
+       case ENXIO:
+               printf("bad device specification\n");
+               break;
+       default:
+               printf("unknown open error\n");
+               break;
+       }
+#endif
+       return (ret);
+}
+
+devclose(io)
+       register struct iob *io;
+{
+       (*devsw[io->i_dev].dv_close)(io);
+}
+
+devioctl(io, cmd, arg)
+       register struct iob *io;
+       int cmd;
+       caddr_t arg;
+{
+       return ((*devsw[io->i_dev].dv_ioctl)(io, cmd, arg));
+}
+
+/* ARGSUSED */
+nullsys(io)
+       struct iob *io;
+{}
+
+/* ARGSUSED */
+nodev(io)
+       struct iob *io;
+{
+       errno = EBADF;
+       return(-1);
+}
+
+/* ARGSUSED */
+noioctl(io, cmd, arg)
+       struct iob *io;
+       int cmd;
+       caddr_t arg;
+{
+       return (ECMD);
+}
diff --git a/usr/src/sys.386bsd/stand/ls.c b/usr/src/sys.386bsd/stand/ls.c
new file mode 100644 (file)
index 0000000..6e18262
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ls.c        7.9 (Berkeley) 6/28/90
+ */
+
+#include "sys/param.h"
+#include "ufs/dir.h"
+#include "saio.h"
+#include "sys/ttychars.h"
+
+main()
+{
+       struct dinode *ip;
+       int fd;
+
+       for (;;) {
+               if ((fd = getfile("ls", 0)) == -1)
+                       exit();
+               ip = &iob[fd - 3].i_ino;
+               if ((ip->di_mode & IFMT) != IFDIR) {
+                       printf("ls: not a directory\n");
+                       continue;
+               }
+               if (ip->di_size == 0) {
+                       printf("ls: zero length directory\n");
+                       continue;
+               }
+               ls(fd);
+       }
+}
+
+#define CTRL(x)        (x&037)
+
+getfile(prompt, mode)
+       char *prompt;
+       int mode;
+{
+       int fd;
+       char buf[100];
+
+       do {
+               printf("%s: ", prompt);
+               gets(buf);
+               if (buf[0] == CTRL('d') && buf[1] == 0)
+                       return (-1);
+       } while ((fd = open(buf, mode)) <= 0);
+       return(fd);
+}
+
+typedef struct direct  DP;
+static
+ls(fd)
+       register int fd;
+{
+       register int size;
+       register char *dp;
+       char dirbuf[DIRBLKSIZ];
+
+       printf("\ninode\tname\n");
+       while ((size = read(fd, dirbuf, DIRBLKSIZ)) == DIRBLKSIZ)
+               for(dp = dirbuf; (dp < (dirbuf + size)) &&
+                   (dp + ((DP *)dp)->d_reclen) < (dirbuf + size);
+                   dp += ((DP *)dp)->d_reclen) {
+                       if (((DP *)dp)->d_ino == 0)
+                               continue;
+                       if (((DP *)dp)->d_namlen > MAXNAMLEN+1) {
+                               printf("Corrupt file name length!  Run fsck soon!\n");
+                               return;
+                       }
+                       printf("%d\t%s\n", ((DP *)dp)->d_ino,
+                           ((DP *)dp)->d_name);
+               }
+}
diff --git a/usr/src/sys.386bsd/stand/saerrno.h b/usr/src/sys.386bsd/stand/saerrno.h
new file mode 100644 (file)
index 0000000..3a2127e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)saerrno.h   7.3 (Berkeley) 6/28/90
+ */
+
+extern int errno;      /* just like unix */
+
+/* error codes */
+#define        EADAPT  1       /* bad adaptor */
+#define        ECTLR   2       /* bad controller */
+#define        EUNIT   3       /* bad drive */
+#define        EPART   4       /* bad partition */
+#define        ERDLAB  5       /* can't read disk label */
+#define        EUNLAB  6       /* unlabeled disk */
+#define        ENXIO   7       /* bad device specification */
+#define        EBADF   8       /* bad file descriptor */
+#define        EOFFSET 9       /* relative seek not supported */
+#define        ESRCH   10      /* directory search for file failed */
+#define        EIO     11      /* generic error */
+#define        ECMD    12      /* undefined driver command */
+#define        EBSE    13      /* bad sector error */
+#define        EWCK    14      /* write check error */
+#define        EECC    15      /* uncorrectable ecc error */
+#define        EHER    16      /* hard error */
diff --git a/usr/src/sys.386bsd/stand/saioctl.h b/usr/src/sys.386bsd/stand/saioctl.h
new file mode 100644 (file)
index 0000000..6d49304
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)saioctl.h   7.4 (Berkeley) 6/28/90
+ */
+
+/* ioctl's -- for disks just now */
+#define        SAIOHDR         (('d'<<8)|1)    /* next i/o includes header */
+#define        SAIOCHECK       (('d'<<8)|2)    /* next i/o checks data */
+#define        SAIOHCHECK      (('d'<<8)|3)    /* next i/o checks header & data */
+#define        SAIONOBAD       (('d'<<8)|4)    /* inhibit bad sector forwarding */
+#define        SAIODOBAD       (('d'<<8)|5)    /* enable bad sector forwarding */
+#define        SAIOECCLIM      (('d'<<8)|6)    /* set limit to ecc correction, bits */
+#define        SAIOECCUNL      (('d'<<8)|7)    /* use standard ecc procedures */
+#define        SAIORETRIES     (('d'<<8)|8)    /* set retry count for unit */
+#define        SAIODEVDATA     (('d'<<8)|9)    /* get pointer to pack label */
+#define        SAIOSSI         (('d'<<8)|10)   /* set skip sector inhibit */
+#define        SAIONOSSI       (('d'<<8)|11)   /* inhibit skip sector handling */
+#define        SAIOSSDEV       (('d'<<8)|12)   /* is device skip sector type? */
+#define        SAIODEBUG       (('d'<<8)|13)   /* enable/disable debugging */
+#define        SAIOGBADINFO    (('d'<<8)|14)   /* get bad-sector table */
diff --git a/usr/src/sys.386bsd/stand/stat.c b/usr/src/sys.386bsd/stand/stat.c
new file mode 100644 (file)
index 0000000..d75f5f6
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)stat.c      7.1 (Berkeley) 5/5/91
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "saio.h"
+
+#ifndef SMALL
+fstat(fd, sb)
+       int fd;
+       struct stat *sb;
+{
+       register struct iob *io;
+
+       fd -= 3;
+       if (fd < 0 || fd >= SOPEN_MAX ||
+           ((io = &iob[fd])->i_flgs & F_ALLOC) == 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       /* only important stuff */
+       sb->st_mode = io->i_ino.di_mode;
+       sb->st_uid = io->i_ino.di_uid;
+       sb->st_gid = io->i_ino.di_gid;
+       sb->st_size = io->i_ino.di_size;
+       return (0);
+}
+
+stat(str, sb)
+       const char *str;
+       struct stat *sb;
+{
+       int fd, rv;
+
+       fd = open(str, 0);
+       if (fd < 0)
+               return(-1);
+       rv = fstat(fd, sb);
+       close(fd);
+       return(rv);
+}
+#endif SMALL
diff --git a/usr/src/sys.386bsd/sys/acct.h b/usr/src/sys.386bsd/sys/acct.h
new file mode 100644 (file)
index 0000000..110eca4
--- /dev/null
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)acct.h      7.3 (Berkeley) 2/15/91
+ */
+
+/*
+ * Accounting structures; these use a comp_t type which is a 3 bits base 8
+ * exponent, 13 bit fraction ``floating point'' number.  Units are 1/AHZ
+ * seconds.
+ */
+typedef u_short comp_t;
+
+struct acct {
+       char    ac_comm[10];    /* command name */
+       comp_t  ac_utime;       /* user time */
+       comp_t  ac_stime;       /* system time */
+       comp_t  ac_etime;       /* elapsed time */
+       time_t  ac_btime;       /* starting time */
+       uid_t   ac_uid;         /* user id */
+       gid_t   ac_gid;         /* group id */
+       short   ac_mem;         /* average memory usage */
+       comp_t  ac_io;          /* count of IO blocks */
+       dev_t   ac_tty;         /* controlling tty */
+#define        AFORK   0x01                    /* forked but not execed */
+#define        ASU     0x02                    /* used super-user permissions */
+#define        ACOMPAT 0x04                    /* used compatibility mode */
+#define        ACORE   0x08                    /* dumped core */
+#define        AXSIG   0x10                    /* killed by a signal */
+       char    ac_flag;        /* accounting flags */
+};
+
+/*
+ * 1/AHZ is the granularity of the data encoded in the comp_t fields.
+ * This is not necessarily equal to hz.
+ */
+#define        AHZ     64
+
+#ifdef KERNEL
+struct vnode   *acctp;
+#endif
diff --git a/usr/src/sys.386bsd/sys/callout.h b/usr/src/sys.386bsd/sys/callout.h
new file mode 100644 (file)
index 0000000..522be36
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)callout.h   7.2 (Berkeley) 2/15/91
+ */
+
+struct callout {
+       struct callout *c_next;         /* next callout in queue */
+       caddr_t c_arg;                  /* function argument */
+       int (*c_func)();                /* function to call */
+       int c_time;                     /* ticks to the event */
+};
+
+#ifdef KERNEL
+struct callout *callfree, *callout, calltodo;
+int ncallout;
+#endif
diff --git a/usr/src/sys.386bsd/sys/cdefs.h b/usr/src/sys.386bsd/sys/cdefs.h
new file mode 100644 (file)
index 0000000..fbe572a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)cdefs.h     7.6 (Berkeley) 5/4/91
+ */
+
+#ifndef        _CDEFS_H_
+#define        _CDEFS_H_
+
+#if defined(__cplusplus)
+#define        __BEGIN_DECLS   extern "C" {
+#define        __END_DECLS     };
+#else
+#define        __BEGIN_DECLS
+#define        __END_DECLS
+#endif
+
+/*
+ * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
+ * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
+ * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
+ * in between its arguments.  __CONCAT can also concatenate double-quoted
+ * strings produced by the __STRING macro, but this only works with ANSI C.
+ */
+#if defined(__STDC__) || defined(__cplusplus)
+#define        __P(protos)     protos          /* full-blown ANSI C */
+#define        __CONCAT(x,y)   x ## y
+#define        __STRING(x)     #x
+
+#else  /* !(__STDC__ || __cplusplus) */
+#define        __P(protos)     ()              /* traditional C preprocessor */
+#define        __CONCAT(x,y)   x/**/y
+#define        __STRING(x)     "x"
+
+#ifdef __GNUC__
+#define        const           __const         /* GCC: ANSI C with -traditional */
+#define        inline          __inline
+#define        signed          __signed
+#define        volatile        __volatile
+
+#else  /* !__GNUC__ */
+#define        const                           /* delete ANSI C keywords */
+#define        inline
+#define        signed
+#define        volatile
+#endif /* !__GNUC__ */
+#endif /* !(__STDC__ || __cplusplus) */
+
+#endif /* !_CDEFS_H_ */
diff --git a/usr/src/sys.386bsd/sys/clist.h b/usr/src/sys.386bsd/sys/clist.h
new file mode 100644 (file)
index 0000000..7181093
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)clist.h     7.3 (Berkeley) 2/15/91
+ */
+
+struct cblock {
+       struct cblock *c_next;          /* next cblock in queue */
+       char c_quote[CBQSIZE];          /* quoted characters */
+       char c_info[CBSIZE];            /* characters */
+};
+
+#ifdef KERNEL
+struct cblock *cfree, *cfreelist;
+int cfreecount, nclist;
+#endif
diff --git a/usr/src/sys.386bsd/sys/conf.h b/usr/src/sys.386bsd/sys/conf.h
new file mode 100644 (file)
index 0000000..ac60340
--- /dev/null
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)conf.h      7.9 (Berkeley) 5/5/91
+ */
+
+/*
+ * Definitions of device driver entry switches
+ */
+
+#ifdef __STDC__
+struct tty;
+#endif
+
+struct bdevsw {
+       int     (*d_open)       __P((dev_t dev, int oflags, int devtype,
+                                    struct proc *p));
+       int     (*d_close)      __P((dev_t dev, int fflag, int devtype,
+                                    struct proc *));
+       int     (*d_strategy)   __P((struct buf *bp));
+       int     (*d_ioctl)      __P((dev_t dev, int cmd, caddr_t data,
+                                    int fflag, struct proc *p));
+       int     (*d_dump)       __P((dev_t dev));
+       int     (*d_psize)      __P((dev_t dev));
+       int     d_flags;
+};
+
+#ifdef KERNEL
+struct bdevsw bdevsw[];
+#endif
+
+struct cdevsw {
+       int     (*d_open)       __P((dev_t dev, int oflags, int devtype,
+                                    struct proc *p));
+       int     (*d_close)      __P((dev_t dev, int fflag, int devtype,
+                                    struct proc *));
+       int     (*d_read)       __P((dev_t dev, struct uio *uio, int ioflag));
+       int     (*d_write)      __P((dev_t dev, struct uio *uio, int ioflag));
+       int     (*d_ioctl)      __P((dev_t dev, int cmd, caddr_t data,
+                                    int fflag, struct proc *p));
+       int     (*d_stop)       __P((struct tty *tp, int rw));
+       int     (*d_reset)      __P((int uban));        /* XXX */
+       struct  tty *d_ttys;
+       int     (*d_select)     __P((dev_t dev, int which, struct proc *p));
+       int     (*d_mmap)       __P(());
+       int     (*d_strategy)   __P((struct buf *bp));
+};
+
+#ifdef KERNEL
+struct cdevsw cdevsw[];
+
+/* symbolic sleep message strings */
+extern char devopn[], devio[], devwait[], devin[], devout[];
+extern char devioc[], devcls[];
+#endif
+
+struct linesw {
+       int     (*l_open)();
+       int     (*l_close)();
+       int     (*l_read)();
+       int     (*l_write)();
+       int     (*l_ioctl)();
+       int     (*l_rint)();
+       int     (*l_rend)();
+       int     (*l_meta)();
+       int     (*l_start)();
+       int     (*l_modem)();
+};
+
+#ifdef KERNEL
+struct linesw linesw[];
+#endif
+
+struct swdevt {
+       dev_t   sw_dev;
+       int     sw_freed;
+       int     sw_nblks;
+       struct  vnode *sw_vp;
+};
+
+#ifdef KERNEL
+struct swdevt swdevt[];
+#endif
diff --git a/usr/src/sys.386bsd/sys/dir.h b/usr/src/sys.386bsd/sys/dir.h
new file mode 100644 (file)
index 0000000..bc4ca3f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dir.h       7.3 (Berkeley) 2/5/91
+ */
+
+/*
+ * The information in this file should be obtained from <dirent.h>
+ * and is provided solely (and temporarily) for backward compatibility.
+ */
+
+#ifndef _DIR_H_
+#define        _DIR_H_
+
+#include <dirent.h>
+
+/*
+ * Backwards compatibility.
+ */
+#define direct dirent
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry.  This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#undef DIRSIZ
+#define DIRSIZ(dp) \
+    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+
+#endif /* !_DIR_H_ */
diff --git a/usr/src/sys.386bsd/sys/dkbad.h b/usr/src/sys.386bsd/sys/dkbad.h
new file mode 100644 (file)
index 0000000..9857d97
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dkbad.h     7.2 (Berkeley) 2/15/91
+ */
+
+/*
+ * Definitions needed to perform bad sector revectoring ala DEC STD 144.
+ *
+ * The bad sector information is located in the first 5 even numbered
+ * sectors of the last track of the disk pack.  There are five identical
+ * copies of the information, described by the dkbad structure.
+ *
+ * Replacement sectors are allocated starting with the first sector before
+ * the bad sector information and working backwards towards the beginning of
+ * the disk.  A maximum of 126 bad sectors are supported.  The position of
+ * the bad sector in the bad sector table determines which replacement sector
+ * it corresponds to.
+ *
+ * The bad sector information and replacement sectors are conventionally
+ * only accessible through the 'c' file system partition of the disk.  If
+ * that partition is used for a file system, the user is responsible for
+ * making sure that it does not overlap the bad sector information or any
+ * replacement sectors.
+ */
+struct dkbad {
+       long bt_csn;                    /* cartridge serial number */
+       u_short bt_mbz;                 /* unused; should be 0 */
+       u_short bt_flag;                /* -1 => alignment cartridge */
+       struct bt_bad {
+               u_short bt_cyl;         /* cylinder number of bad sector */
+               u_short bt_trksec;      /* track and sector number */
+       } bt_bad[126];
+};
+
+#define        ECC     0
+#define        SSE     1
+#define        BSE     2
+#define        CONT    3
diff --git a/usr/src/sys.386bsd/sys/dkstat.h b/usr/src/sys.386bsd/sys/dkstat.h
new file mode 100644 (file)
index 0000000..320c65d
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dkstat.h    7.5 (Berkeley) 2/15/91
+ */
+
+#define        CP_USER         0
+#define        CP_NICE         1
+#define        CP_SYS          2
+#define        CP_IDLE         3
+#define        CPUSTATES       4
+
+#define        DK_NDRIVE       8
+#ifdef KERNEL
+long cp_time[CPUSTATES];
+long dk_seek[DK_NDRIVE];
+long dk_time[DK_NDRIVE];
+long dk_wds[DK_NDRIVE];
+long dk_wpms[DK_NDRIVE];
+long dk_xfer[DK_NDRIVE];
+
+int dk_busy;
+int dk_ndrive;
+
+long tk_cancc;
+long tk_nin;
+long tk_nout;
+long tk_rawcc;
+#endif
diff --git a/usr/src/sys.386bsd/sys/dmap.h b/usr/src/sys.386bsd/sys/dmap.h
new file mode 100644 (file)
index 0000000..5284b41
--- /dev/null
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dmap.h      7.3 (Berkeley) 2/15/91
+ */
+
+#ifndef _DMAP_H_
+#define        _DMAP_H_
+
+/*
+ * Definitions for the mapping of vitual swap space to the physical swap
+ * area - the disk map.
+ */
+#define        NDMAP   38              /* size of the swap area map */
+
+struct dmap {
+       swblk_t dm_size;        /* current size used by process */
+       swblk_t dm_alloc;       /* amount of physical swap space allocated */
+       swblk_t dm_map[NDMAP];  /* first disk block number in each chunk */
+};
+#ifdef KERNEL
+struct dmap zdmap;
+int dmmin, dmmax, dmtext;
+#endif
+
+/* The following structure is that ``returned'' from a call to vstodb(). */
+struct dblock {
+       swblk_t db_base;        /* base of physical contig drum block */
+       swblk_t db_size;        /* size of block */
+};
+#endif /* !_DMAP_H_ */
diff --git a/usr/src/sys.386bsd/sys/domain.h b/usr/src/sys.386bsd/sys/domain.h
new file mode 100644 (file)
index 0000000..9555516
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)domain.h    7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Structure per communications domain.
+ */
+struct domain {
+       int     dom_family;             /* AF_xxx */
+       char    *dom_name;
+       int     (*dom_init)();          /* initialize domain data structures */
+       int     (*dom_externalize)();   /* externalize access rights */
+       int     (*dom_dispose)();       /* dispose of internalized rights */
+       struct  protosw *dom_protosw, *dom_protoswNPROTOSW;
+       struct  domain *dom_next;
+};
+
+#ifdef KERNEL
+struct domain *domains;
+#endif
diff --git a/usr/src/sys.386bsd/sys/errno.h b/usr/src/sys.386bsd/sys/errno.h
new file mode 100644 (file)
index 0000000..8869d59
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)errno.h     7.13 (Berkeley) 2/19/91
+ */
+
+#ifndef KERNEL
+extern int errno;                      /* global error number */
+#endif
+
+#define        EPERM           1               /* Operation not permitted */
+#define        ENOENT          2               /* No such file or directory */
+#define        ESRCH           3               /* No such process */
+#define        EINTR           4               /* Interrupted system call */
+#define        EIO             5               /* Input/output error */
+#define        ENXIO           6               /* Device not configured */
+#define        E2BIG           7               /* Argument list too long */
+#define        ENOEXEC         8               /* Exec format error */
+#define        EBADF           9               /* Bad file descriptor */
+#define        ECHILD          10              /* No child processes */
+#define        EDEADLK         11              /* Resource deadlock avoided */
+                                       /* 11 was EAGAIN */
+#define        ENOMEM          12              /* Cannot allocate memory */
+#define        EACCES          13              /* Permission denied */
+#define        EFAULT          14              /* Bad address */
+#ifndef _POSIX_SOURCE
+#define        ENOTBLK         15              /* Block device required */
+#define        EBUSY           16              /* Device busy */
+#endif
+#define        EEXIST          17              /* File exists */
+#define        EXDEV           18              /* Cross-device link */
+#define        ENODEV          19              /* Operation not supported by device */
+#define        ENOTDIR         20              /* Not a directory */
+#define        EISDIR          21              /* Is a directory */
+#define        EINVAL          22              /* Invalid argument */
+#define        ENFILE          23              /* Too many open files in system */
+#define        EMFILE          24              /* Too many open files */
+#define        ENOTTY          25              /* Inappropriate ioctl for device */
+#ifndef _POSIX_SOURCE
+#define        ETXTBSY         26              /* Text file busy */
+#endif
+#define        EFBIG           27              /* File too large */
+#define        ENOSPC          28              /* No space left on device */
+#define        ESPIPE          29              /* Illegal seek */
+#define        EROFS           30              /* Read-only file system */
+#define        EMLINK          31              /* Too many links */
+#define        EPIPE           32              /* Broken pipe */
+
+/* math software */
+#define        EDOM            33              /* Numerical argument out of domain */
+#define        ERANGE          34              /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define        EAGAIN          35              /* Resource temporarily unavailable */
+#ifndef _POSIX_SOURCE
+#define        EWOULDBLOCK     EAGAIN          /* Operation would block */
+#define        EINPROGRESS     36              /* Operation now in progress */
+#define        EALREADY        37              /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define        ENOTSOCK        38              /* Socket operation on non-socket */
+#define        EDESTADDRREQ    39              /* Destination address required */
+#define        EMSGSIZE        40              /* Message too long */
+#define        EPROTOTYPE      41              /* Protocol wrong type for socket */
+#define        ENOPROTOOPT     42              /* Protocol not available */
+#define        EPROTONOSUPPORT 43              /* Protocol not supported */
+#define        ESOCKTNOSUPPORT 44              /* Socket type not supported */
+#define        EOPNOTSUPP      45              /* Operation not supported on socket */
+#define        EPFNOSUPPORT    46              /* Protocol family not supported */
+#define        EAFNOSUPPORT    47              /* Address family not supported by protocol family */
+#define        EADDRINUSE      48              /* Address already in use */
+#define        EADDRNOTAVAIL   49              /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define        ENETDOWN        50              /* Network is down */
+#define        ENETUNREACH     51              /* Network is unreachable */
+#define        ENETRESET       52              /* Network dropped connection on reset */
+#define        ECONNABORTED    53              /* Software caused connection abort */
+#define        ECONNRESET      54              /* Connection reset by peer */
+#define        ENOBUFS         55              /* No buffer space available */
+#define        EISCONN         56              /* Socket is already connected */
+#define        ENOTCONN        57              /* Socket is not connected */
+#define        ESHUTDOWN       58              /* Can't send after socket shutdown */
+#define        ETOOMANYREFS    59              /* Too many references: can't splice */
+#define        ETIMEDOUT       60              /* Connection timed out */
+#define        ECONNREFUSED    61              /* Connection refused */
+
+#define        ELOOP           62              /* Too many levels of symbolic links */
+#endif /* _POSIX_SOURCE */
+#define        ENAMETOOLONG    63              /* File name too long */
+
+/* should be rearranged */
+#ifndef _POSIX_SOURCE
+#define        EHOSTDOWN       64              /* Host is down */
+#define        EHOSTUNREACH    65              /* No route to host */
+#endif /* _POSIX_SOURCE */
+#define        ENOTEMPTY       66              /* Directory not empty */
+
+/* quotas & mush */
+#ifndef _POSIX_SOURCE
+#define        EPROCLIM        67              /* Too many processes */
+#define        EUSERS          68              /* Too many users */
+#define        EDQUOT          69              /* Disc quota exceeded */
+
+/* Network File System */
+#define        ESTALE          70              /* Stale NFS file handle */
+#define        EREMOTE         71              /* Too many levels of remote in path */
+#define        EBADRPC         72              /* RPC struct is bad */
+#define        ERPCMISMATCH    73              /* RPC version wrong */
+#define        EPROGUNAVAIL    74              /* RPC prog. not avail */
+#define        EPROGMISMATCH   75              /* Program version wrong */
+#define        EPROCUNAVAIL    76              /* Bad procedure for program */
+#endif /* _POSIX_SOURCE */
+
+#define        ENOLCK          77              /* No locks available */
+#define        ENOSYS          78              /* Function not implemented */
+
+#define        EFTYPE          79              /* Inappropriate file type or format */
+
+#ifdef KERNEL
+/* pseudo-errors returned inside kernel to modify return to process */
+#define        ERESTART        -1              /* restart syscall */
+#define        EJUSTRETURN     -2              /* don't modify regs, just return */
+#endif
diff --git a/usr/src/sys.386bsd/sys/exec.h b/usr/src/sys.386bsd/sys/exec.h
new file mode 100644 (file)
index 0000000..ec539d9
--- /dev/null
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)exec.h      7.5 (Berkeley) 2/15/91
+ */
+
+#ifndef        _EXEC_H_
+#define        _EXEC_H_
+
+/* Header prepended to each a.out file. */
+struct exec {
+#if !defined(vax) && !defined(tahoe) && !defined(i386)
+unsigned short a_mid;          /* machine ID */
+unsigned short a_magic;        /* magic number */
+#else
+        long   a_magic;        /* magic number */
+#endif
+unsigned long  a_text;         /* text segment size */
+unsigned long  a_data;         /* initialized data size */
+unsigned long  a_bss;          /* uninitialized data size */
+unsigned long  a_syms;         /* symbol table size */
+unsigned long  a_entry;        /* entry point */
+unsigned long  a_trsize;       /* text relocation size */
+unsigned long  a_drsize;       /* data relocation size */
+};
+#define        a_machtype      a_mid   /* SUN compatibility */
+
+/* a_magic */
+#define        OMAGIC          0407    /* old impure format */
+#define        NMAGIC          0410    /* read-only text */
+#define        ZMAGIC          0413    /* demand load format */
+
+/* a_mid */
+#define        MID_ZERO        0       /* unknown - implementation dependent */
+#define        MID_SUN010      1       /* sun 68010/68020 binary */
+#define        MID_SUN020      2       /* sun 68020-only binary */
+#define        MID_HP200       200     /* hp200 (68010) BSD binary */
+#define        MID_HP300       300     /* hp300 (68020+68881) BSD binary */
+#define        MID_HPUX        0x20C   /* hp200/300 HP-UX binary */
+#define        MID_HPUX800     0x20B   /* hp800 HP-UX binary */
+
+#endif /* !_EXEC_H_ */
diff --git a/usr/src/sys.386bsd/sys/fcntl.h b/usr/src/sys.386bsd/sys/fcntl.h
new file mode 100644 (file)
index 0000000..cc72bca
--- /dev/null
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1983, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)fcntl.h     5.14 (Berkeley) 7/1/91
+ */
+
+#ifndef _FCNTL_H_
+#define        _FCNTL_H_
+
+/*
+ * This file includes the definitions for open and fcntl
+ * described by POSIX for <fcntl.h>; it also includes
+ * related kernel definitions.
+ */
+
+#ifndef KERNEL
+#include <sys/types.h>
+#endif
+
+/*
+ * File status flags: these are used by open(2), fcntl(2).
+ * They are also used (indirectly) in the kernel file structure f_flags,
+ * which is a superset of the open/fcntl flags.  Open flags and f_flags
+ * are inter-convertible using OFLAGS(fflags) and FFLAGS(oflags).
+ * Open/fcntl flags begin with O_; kernel-internal flags begin with F.
+ */
+/* open-only flags */
+#define        O_RDONLY        0x0000          /* open for reading only */
+#define        O_WRONLY        0x0001          /* open for writing only */
+#define        O_RDWR          0x0002          /* open for reading and writing */
+#define        O_ACCMODE       0x0003          /* mask for above modes */
+
+#ifdef KERNEL
+/*
+ * Kernel encoding of open mode; separate read and write bits
+ * that are independently testable: 1 greater than the above.
+ */
+#define        FREAD           0x0001
+#define        FWRITE          0x0002
+#endif
+#define        O_NONBLOCK      0x0004          /* no delay */
+#define        O_APPEND        0x0008          /* set append mode */
+#ifndef _POSIX_SOURCE
+#define        O_SHLOCK        0x0010          /* open with shared file lock */
+#define        O_EXLOCK        0x0020          /* open with exclusive file lock */
+#define        O_ASYNC         0x0040          /* signal pgrp when data ready */
+#define        O_FSYNC         0x0080          /* synchronous writes */
+#endif
+#define        O_CREAT         0x0200          /* create if nonexistant */
+#define        O_TRUNC         0x0400          /* truncate to zero length */
+#define        O_EXCL          0x0800          /* error if already exists */
+#ifdef KERNEL
+#define        FMARK           0x1000          /* mark during gc() */
+#define        FDEFER          0x2000          /* defer for next gc pass */
+#define        FHASLOCK        0x4000          /* descriptor holds advisory lock */
+#endif
+
+/* defined by POSIX 1003.1; BSD default, so no bit required */
+#define        O_NOCTTY        0               /* don't assign controlling terminal */
+
+#ifdef KERNEL
+/* convert from open() flags to/from fflags; convert O_RD/WR to FREAD/FWRITE */
+#define        FFLAGS(oflags)  ((oflags) + 1)
+#define        OFLAGS(fflags)  ((fflags) - 1)
+
+/* bits to save after open */
+#define        FMASK           (FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK)
+/* bits settable by fcntl(F_SETFL, ...) */
+#define        FCNTLFLAGS      (FAPPEND|FASYNC|FFSYNC|FNONBLOCK)
+#endif
+
+/*
+ * The O_* flags used to have only F* names, which were used in the kernel
+ * and by fcntl.  We retain the F* names for the kernel f_flags field
+ * and for backward compatibility for fcntl.
+ */
+#ifndef _POSIX_SOURCE
+#define        FAPPEND         O_APPEND        /* kernel/compat */
+#define        FASYNC          O_ASYNC         /* kernel/compat */
+#define        FFSYNC          O_FSYNC         /* kernel */
+#define        FNONBLOCK       O_NONBLOCK      /* kernel */
+#define        FNDELAY         O_NONBLOCK      /* compat */
+#define        O_NDELAY        O_NONBLOCK      /* compat */
+#endif
+
+/*
+ * Constants used for fcntl(2)
+ */
+
+/* command values */
+#define        F_DUPFD         0               /* duplicate file descriptor */
+#define        F_GETFD         1               /* get file descriptor flags */
+#define        F_SETFD         2               /* set file descriptor flags */
+#define        F_GETFL         3               /* get file status flags */
+#define        F_SETFL         4               /* set file status flags */
+#ifndef _POSIX_SOURCE
+#define        F_GETOWN        5               /* get SIGIO/SIGURG proc/pgrp */
+#define F_SETOWN       6               /* set SIGIO/SIGURG proc/pgrp */
+#endif
+#define        F_GETLK         7               /* get record locking information */
+#define        F_SETLK         8               /* set record locking information */
+#define        F_SETLKW        9               /* F_SETLK; wait if blocked */
+
+/* file descriptor flags (F_GETFD, F_SETFD) */
+#define        FD_CLOEXEC      1               /* close-on-exec flag */
+
+/* record locking flags (F_GETLK, F_SETLK, F_SETLKW) */
+#define        F_RDLCK         1               /* shared or read lock */
+#define        F_UNLCK         2               /* unlock */
+#define        F_WRLCK         3               /* exclusive or write lock */
+#ifdef KERNEL
+#define        F_WAIT          0x010           /* Wait until lock is granted */
+#define        F_FLOCK         0x020           /* Use flock(2) semantics for lock */
+#define        F_POSIX         0x040           /* Use POSIX semantics for lock */
+#endif
+
+/*
+ * Advisory file segment locking data type -
+ * information passed to system by user
+ */
+struct flock {
+       short   l_type;         /* lock type: read/write, etc. */
+       short   l_whence;       /* type of l_start */
+       off_t   l_start;        /* starting offset */
+       off_t   l_len;          /* len = 0 means until end of file */
+       pid_t   l_pid;          /* lock owner */
+};
+
+
+#ifndef _POSIX_SOURCE
+/* lock operations for flock(2) */
+#define        LOCK_SH         0x01            /* shared file lock */
+#define        LOCK_EX         0x02            /* exclusive file lock */
+#define        LOCK_NB         0x04            /* don't block when locking */
+#define        LOCK_UN         0x08            /* unlock file */
+#endif
+
+
+#ifndef KERNEL
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    open __P((const char *, int, ...));
+int    creat __P((const char *, mode_t));
+int    fcntl __P((int, int, ...));
+#ifndef _POSIX_SOURCE
+int    flock __P((int, int));
+#endif /* !_POSIX_SOURCE */
+__END_DECLS
+#endif
+
+#endif /* !_FCNTL_H_ */
diff --git a/usr/src/sys.386bsd/sys/fifo.h b/usr/src/sys.386bsd/sys/fifo.h
new file mode 100644 (file)
index 0000000..4ddd510
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)fifo.h      7.1 (Berkeley) 4/15/91
+ */
+
+#ifdef FIFO
+/*
+ * Prototypes for fifo operations on vnodes.
+ */
+int    fifo_badop(),
+       fifo_ebadf();
+
+int    fifo_lookup __P((
+               struct vnode *vp,
+               struct nameidata *ndp,
+               struct proc *p));
+#define fifo_create ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) fifo_badop)
+#define fifo_mknod ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) fifo_badop)
+int    fifo_open __P((
+               struct vnode *vp,
+               int mode,
+               struct ucred *cred,
+               struct proc *p));
+int    fifo_close __P((
+               struct vnode *vp,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+#define fifo_access ((int (*) __P(( \
+               struct vnode *vp, \
+               int mode, \
+               struct ucred *cred, \
+               struct proc *p))) fifo_ebadf)
+#define fifo_getattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) fifo_ebadf)
+#define fifo_setattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) fifo_ebadf)
+int    fifo_read __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+int    fifo_write __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+int    fifo_ioctl __P((
+               struct vnode *vp,
+               int command,
+               caddr_t data,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+int    fifo_select __P((
+               struct vnode *vp,
+               int which,
+               int fflags,
+               struct ucred *cred,
+               struct proc *p));
+#define fifo_mmap ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               struct proc *p))) fifo_badop)
+#define fifo_fsync ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               int waitfor, \
+               struct proc *p))) nullop)
+#define fifo_seek ((int (*) __P(( \
+               struct vnode *vp, \
+               off_t oldoff, \
+               off_t newoff, \
+               struct ucred *cred))) fifo_badop)
+#define fifo_remove ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) fifo_badop)
+#define fifo_link ((int (*) __P(( \
+               struct vnode *vp, \
+               struct nameidata *ndp, \
+               struct proc *p))) fifo_badop)
+#define fifo_rename ((int (*) __P(( \
+               struct nameidata *fndp, \
+               struct nameidata *tdnp, \
+               struct proc *p))) fifo_badop)
+#define fifo_mkdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) fifo_badop)
+#define fifo_rmdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) fifo_badop)
+#define fifo_symlink ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               char *target, \
+               struct proc *p))) fifo_badop)
+#define fifo_readdir ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred, \
+               int *eofflagp))) fifo_badop)
+#define fifo_readlink ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred))) fifo_badop)
+#define fifo_abortop ((int (*) __P(( \
+               struct nameidata *ndp))) fifo_badop)
+#define fifo_inactive ((int (*) __P(( \
+               struct vnode *vp, \
+               struct proc *p))) nullop)
+#define fifo_reclaim ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+int    fifo_lock __P((
+               struct vnode *vp));
+int    fifo_unlock __P((
+               struct vnode *vp));
+int    fifo_bmap __P((
+               struct vnode *vp,
+               daddr_t bn,
+               struct vnode **vpp,
+               daddr_t *bnp));
+#define fifo_strategy ((int (*) __P(( \
+               struct buf *bp))) fifo_badop)
+int    fifo_print __P((
+               struct vnode *vp));
+#define fifo_islocked ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+int    fifo_advlock __P((
+               struct vnode *vp,
+               caddr_t id,
+               int op,
+               struct flock *fl,
+               int flags));
+#endif /* FIFO */
diff --git a/usr/src/sys.386bsd/sys/file.h b/usr/src/sys.386bsd/sys/file.h
new file mode 100644 (file)
index 0000000..31f1989
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)file.h      7.10 (Berkeley) 6/4/91
+ */
+
+#include <sys/fcntl.h>
+#include <sys/unistd.h>
+
+#ifdef KERNEL
+/*
+ * Kernel descriptor table.
+ * One entry for each open kernel vnode and socket.
+ */
+struct file {
+       struct  file *f_filef;  /* list of active files */
+       struct  file **f_fileb; /* list of active files */
+       short   f_flag;         /* see fcntl.h */
+#define        DTYPE_VNODE     1       /* file */
+#define        DTYPE_SOCKET    2       /* communications endpoint */
+       short   f_type;         /* descriptor type */
+       short   f_count;        /* reference count */
+       short   f_msgcount;     /* references from message queue */
+       struct  ucred *f_cred;  /* credentials associated with descriptor */
+       struct  fileops {
+               int     (*fo_read)      __P((struct file *fp, struct uio *uio,
+                                           struct ucred *cred));
+               int     (*fo_write)     __P((struct file *fp, struct uio *uio,
+                                           struct ucred *cred));
+               int     (*fo_ioctl)     __P((struct file *fp, int com,
+                                           caddr_t data, struct proc *p));
+               int     (*fo_select)    __P((struct file *fp, int which,
+                                           struct proc *p));
+               int     (*fo_close)     __P((struct file *fp, struct proc *p));
+       } *f_ops;
+       off_t   f_offset;
+       caddr_t f_data;         /* vnode or socket */
+};
+
+extern struct file *filehead;  /* head of list of open files */
+extern int maxfiles;           /* kernel limit on number of open files */
+extern int nfiles;             /* actual number of open files */
+
+#endif /* KERNEL */
diff --git a/usr/src/sys.386bsd/sys/filedesc.h b/usr/src/sys.386bsd/sys/filedesc.h
new file mode 100644 (file)
index 0000000..b6243c2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)filedesc.h  7.4 (Berkeley) 5/4/91
+ */
+
+/*
+ * This structure is used for the management of descriptors.  It may be
+ * shared by multiple processes.
+ *
+ * A process is initially started out with NDFILE descriptors stored within
+ * this structure, selected to be enough for typical applications based on
+ * the historical limit of 20 open files (and the usage of descriptors by
+ * shells).  If these descriptors are exhausted, a larger descriptor table
+ * may be allocated, up to a process' resource limit; the internal arrays
+ * are then unused.  The initial expansion is set to NDEXTENT; each time
+ * it runs out, it is doubled until the resource limit is reached. NDEXTENT
+ * should be selected to be the biggest multiple of OFILESIZE (see below)
+ * that will fit in a power-of-two sized piece of memory.
+ */
+#define NDFILE         20
+#define NDEXTENT       50              /* 250 bytes in 256-byte alloc. */ 
+
+struct filedesc {
+       struct  file **fd_ofiles;       /* file structures for open files */
+       char    *fd_ofileflags;         /* per-process open file flags */
+       struct  vnode *fd_cdir;         /* current directory */
+       struct  vnode *fd_rdir;         /* root directory */
+       int     fd_nfiles;              /* number of open files allocated */
+       u_short fd_lastfile;            /* high-water mark of fd_ofiles */
+       u_short fd_freefile;            /* approx. next free file */
+       u_short fd_cmask;               /* mask for file creation */
+       u_short fd_refcnt;              /* reference count */
+};
+
+/*
+ * Basic allocation of descriptors:
+ * one of the above, plus arrays for NDFILE descriptors.
+ */
+struct filedesc0 {
+       struct  filedesc fd_fd;
+       /*
+        * These arrays are used when the number of open files is
+        * <= NDFILE, and are then pointed to by the pointers above.
+        */
+       struct  file *fd_dfiles[NDFILE];
+       char    fd_dfileflags[NDFILE];
+};
+
+/*
+ * Per-process open flags.
+ */
+#define        UF_EXCLOSE      0x01            /* auto-close on exec */
+#define        UF_MAPPED       0x02            /* mapped from device */
+
+/*
+ * Storage required per open file descriptor.
+ */
+#define OFILESIZE (sizeof(struct file *) + sizeof(char))
+
+#ifdef KERNEL
+/*
+ * Kernel global variables and routines.
+ */
+int    fdalloc __P((struct proc *p, int want, int *result));
+int    fdavail __P((struct proc *p, int n));
+int    falloc __P((struct proc *p, struct file **resultfp, int *resultfd));
+struct filedesc *fdcopy __P((struct proc *p));
+void   fdfree __P((struct proc *p));
+#endif
diff --git a/usr/src/sys.386bsd/sys/gprof.h b/usr/src/sys.386bsd/sys/gprof.h
new file mode 100644 (file)
index 0000000..0316719
--- /dev/null
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)gprof.h     7.2 (Berkeley) 2/15/91
+ */
+
+struct phdr {
+    char       *lpc;
+    char       *hpc;
+    int                ncnt;
+};
+
+    /*
+     * histogram counters are unsigned shorts (according to the kernel).
+     */
+#define        HISTCOUNTER     unsigned short
+
+    /*
+     * fraction of text space to allocate for histogram counters
+     * here, 1/2
+     */
+#define        HISTFRACTION    2
+
+    /*
+     * Fraction of text space to allocate for from hash buckets.
+     * The value of HASHFRACTION is based on the minimum number of bytes
+     * of separation between two subroutine call points in the object code.
+     * Given MIN_SUBR_SEPARATION bytes of separation the value of
+     * HASHFRACTION is calculated as:
+     *
+     *         HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
+     *
+     * For the VAX, the shortest two call sequence is:
+     *
+     *         calls   $0,(r0)
+     *         calls   $0,(r0)
+     *
+     * which is separated by only three bytes, thus HASHFRACTION is 
+     * calculated as:
+     *
+     *         HASHFRACTION = 3 / (2 * 2 - 1) = 1
+     *
+     * Note that the division above rounds down, thus if MIN_SUBR_FRACTION
+     * is less than three, this algorithm will not work!
+     *
+     * NB: for the kernel we assert that the shortest two call sequence is:
+     *
+     *         calls   $0,_name
+     *         calls   $0,_name
+     *
+     * which is separated by seven bytes, thus HASHFRACTION is calculated as:
+     *
+     *         HASHFRACTION = 7 / (2 * 2 - 1) = 2
+     */
+#define        HASHFRACTION    2
+
+    /*
+     * percent of text space to allocate for tostructs
+     * with a minimum.
+     */
+#define ARCDENSITY     2
+#define MINARCS                50
+
+struct tostruct {
+    char               *selfpc;
+    long               count;
+    unsigned short     link;
+};
+
+    /*
+     * a raw arc,
+     *     with pointers to the calling site and the called site
+     *     and a count.
+     */
+struct rawarc {
+    unsigned long      raw_frompc;
+    unsigned long      raw_selfpc;
+    long               raw_count;
+};
+
+    /*
+     * general rounding functions.
+     */
+#define ROUNDDOWN(x,y) (((x)/(y))*(y))
+#define ROUNDUP(x,y)   ((((x)+(y)-1)/(y))*(y))
diff --git a/usr/src/sys.386bsd/sys/ioctl.h b/usr/src/sys.386bsd/sys/ioctl.h
new file mode 100644 (file)
index 0000000..4929a84
--- /dev/null
@@ -0,0 +1,224 @@
+/*-
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ioctl.h     7.19 (Berkeley) 6/26/91
+ */
+
+#ifndef        _IOCTL_H_
+#define        _IOCTL_H_
+
+/*
+ * Window/terminal size structure.  This information is stored by the kernel
+ * in order to provide a consistent interface, but is not used by the kernel.
+ */
+struct winsize {
+       unsigned short  ws_row;         /* rows, in characters */
+       unsigned short  ws_col;         /* columns, in characters */
+       unsigned short  ws_xpixel;      /* horizontal size, pixels */
+       unsigned short  ws_ypixel;      /* vertical size, pixels */
+};
+
+/*
+ * Pun for SUN.
+ */
+struct ttysize {
+       unsigned short  ts_lines;
+       unsigned short  ts_cols;
+       unsigned short  ts_xxx;
+       unsigned short  ts_yyy;
+};
+#define        TIOCGSIZE       TIOCGWINSZ
+#define        TIOCSSIZE       TIOCSWINSZ
+
+/*
+ * Ioctl's have the command encoded in the lower word, and the size of
+ * any in or out parameters in the upper word.  The high 3 bits of the
+ * upper word are used to encode the in/out status of the parameter.
+ */
+#define        IOCPARM_MASK    0x1fff          /* parameter length, at most 13 bits */
+#define        IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
+#define        IOCBASECMD(x)   ((x) & ~IOCPARM_MASK)
+#define        IOCGROUP(x)     (((x) >> 8) & 0xff)
+
+#define        IOCPARM_MAX     NBPG            /* max size of ioctl, mult. of NBPG */
+#define        IOC_VOID        0x20000000      /* no parameters */
+#define        IOC_OUT         0x40000000      /* copy out parameters */
+#define        IOC_IN          0x80000000      /* copy in parameters */
+#define        IOC_INOUT       (IOC_IN|IOC_OUT)
+#define        IOC_DIRMASK     0xe0000000      /* mask for IN/OUT/VOID */
+
+#define _IOC(inout,group,num,len) \
+       (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
+#define        _IO(g,n)        _IOC(IOC_VOID,  (g), (n), 0)
+#define        _IOR(g,n,t)     _IOC(IOC_OUT,   (g), (n), sizeof(t))
+#define        _IOW(g,n,t)     _IOC(IOC_IN,    (g), (n), sizeof(t))
+/* this should be _IORW, but stdio got there first */
+#define        _IOWR(g,n,t)    _IOC(IOC_INOUT, (g), (n), sizeof(t))
+
+#define        TIOCMODG        _IOR('t', 3, int)       /* get modem control state */
+#define        TIOCMODS        _IOW('t', 4, int)       /* set modem control state */
+#define                TIOCM_LE        0001            /* line enable */
+#define                TIOCM_DTR       0002            /* data terminal ready */
+#define                TIOCM_RTS       0004            /* request to send */
+#define                TIOCM_ST        0010            /* secondary transmit */
+#define                TIOCM_SR        0020            /* secondary receive */
+#define                TIOCM_CTS       0040            /* clear to send */
+#define                TIOCM_CAR       0100            /* carrier detect */
+#define                TIOCM_CD        TIOCM_CAR
+#define                TIOCM_RNG       0200            /* ring */
+#define                TIOCM_RI        TIOCM_RNG
+#define                TIOCM_DSR       0400            /* data set ready */
+                                               /* 8-10 compat */
+#define        TIOCEXCL        _IO('t', 13)            /* set exclusive use of tty */
+#define        TIOCNXCL        _IO('t', 14)            /* reset exclusive use of tty */
+                                               /* 15 unused */
+#define        TIOCFLUSH       _IOW('t', 16, int)      /* flush buffers */
+                                               /* 17-18 compat */
+#define        TIOCGETA        _IOR('t', 19, struct termios) /* get termios struct */
+#define        TIOCSETA        _IOW('t', 20, struct termios) /* set termios struct */
+#define        TIOCSETAW       _IOW('t', 21, struct termios) /* drain output, set */
+#define        TIOCSETAF       _IOW('t', 22, struct termios) /* drn out, fls in, set */
+#define        TIOCGETD        _IOR('t', 26, int)      /* get line discipline */
+#define        TIOCSETD        _IOW('t', 27, int)      /* set line discipline */
+                                               /* 127-124 compat */
+#define        TIOCSBRK        _IO('t', 123)           /* set break bit */
+#define        TIOCCBRK        _IO('t', 122)           /* clear break bit */
+#define        TIOCSDTR        _IO('t', 121)           /* set data terminal ready */
+#define        TIOCCDTR        _IO('t', 120)           /* clear data terminal ready */
+#define        TIOCGPGRP       _IOR('t', 119, int)     /* get pgrp of tty */
+#define        TIOCSPGRP       _IOW('t', 118, int)     /* set pgrp of tty */
+                                               /* 117-116 compat */
+#define        TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
+#define        TIOCSTI         _IOW('t', 114, char)    /* simulate terminal input */
+#define        TIOCNOTTY       _IO('t', 113)           /* void tty association */
+#define        TIOCPKT         _IOW('t', 112, int)     /* pty: set/clear packet mode */
+#define                TIOCPKT_DATA            0x00    /* data packet */
+#define                TIOCPKT_FLUSHREAD       0x01    /* flush packet */
+#define                TIOCPKT_FLUSHWRITE      0x02    /* flush packet */
+#define                TIOCPKT_STOP            0x04    /* stop output */
+#define                TIOCPKT_START           0x08    /* start output */
+#define                TIOCPKT_NOSTOP          0x10    /* no more ^S, ^Q */
+#define                TIOCPKT_DOSTOP          0x20    /* now do ^S ^Q */
+#define                TIOCPKT_IOCTL           0x40    /* state change of pty driver */
+#define        TIOCSTOP        _IO('t', 111)           /* stop output, like ^S */
+#define        TIOCSTART       _IO('t', 110)           /* start output, like ^Q */
+#define        TIOCMSET        _IOW('t', 109, int)     /* set all modem bits */
+#define        TIOCMBIS        _IOW('t', 108, int)     /* bis modem bits */
+#define        TIOCMBIC        _IOW('t', 107, int)     /* bic modem bits */
+#define        TIOCMGET        _IOR('t', 106, int)     /* get all modem bits */
+#define        TIOCREMOTE      _IOW('t', 105, int)     /* remote input editing */
+#define        TIOCGWINSZ      _IOR('t', 104, struct winsize)  /* get window size */
+#define        TIOCSWINSZ      _IOW('t', 103, struct winsize)  /* set window size */
+#define        TIOCUCNTL       _IOW('t', 102, int)     /* pty: set/clr usr cntl mode */
+#define                UIOCCMD(n)      _IO('u', n)             /* usr cntl op "n" */
+#define        TIOCCONS        _IOW('t', 98, int)              /* become virtual console */
+#define        TIOCSCTTY       _IO('t', 97)            /* become controlling tty */
+#define        TIOCEXT         _IOW('t', 96, int)      /* pty: external processing */
+#define        TIOCSIG         _IO('t', 95)            /* pty: generate signal */
+#define TIOCDRAIN      _IO('t', 94)            /* wait till output drained */
+
+#define TTYDISC                0               /* termios tty line discipline */
+#define        TABLDISC        3               /* tablet discipline */
+#define        SLIPDISC        4               /* serial IP discipline */
+
+
+#define        FIOCLEX         _IO('f', 1)             /* set close on exec on fd */
+#define        FIONCLEX        _IO('f', 2)             /* remove close on exec */
+#define        FIONREAD        _IOR('f', 127, int)     /* get # bytes to read */
+#define        FIONBIO         _IOW('f', 126, int)     /* set/clear non-blocking i/o */
+#define        FIOASYNC        _IOW('f', 125, int)     /* set/clear async i/o */
+#define        FIOSETOWN       _IOW('f', 124, int)     /* set owner */
+#define        FIOGETOWN       _IOR('f', 123, int)     /* get owner */
+
+/* socket i/o controls */
+#define        SIOCSHIWAT      _IOW('s',  0, int)              /* set high watermark */
+#define        SIOCGHIWAT      _IOR('s',  1, int)              /* get high watermark */
+#define        SIOCSLOWAT      _IOW('s',  2, int)              /* set low watermark */
+#define        SIOCGLOWAT      _IOR('s',  3, int)              /* get low watermark */
+#define        SIOCATMARK      _IOR('s',  7, int)              /* at oob mark? */
+#define        SIOCSPGRP       _IOW('s',  8, int)              /* set process group */
+#define        SIOCGPGRP       _IOR('s',  9, int)              /* get process group */
+
+#define        SIOCADDRT       _IOW('r', 10, struct ortentry)  /* add route */
+#define        SIOCDELRT       _IOW('r', 11, struct ortentry)  /* delete route */
+
+#define        SIOCSIFADDR     _IOW('i', 12, struct ifreq)     /* set ifnet address */
+#define        OSIOCGIFADDR    _IOWR('i',13, struct ifreq)     /* get ifnet address */
+#define        SIOCGIFADDR     _IOWR('i',33, struct ifreq)     /* get ifnet address */
+#define        SIOCSIFDSTADDR  _IOW('i', 14, struct ifreq)     /* set p-p address */
+#define        OSIOCGIFDSTADDR _IOWR('i',15, struct ifreq)     /* get p-p address */
+#define        SIOCGIFDSTADDR  _IOWR('i',34, struct ifreq)     /* get p-p address */
+#define        SIOCSIFFLAGS    _IOW('i', 16, struct ifreq)     /* set ifnet flags */
+#define        SIOCGIFFLAGS    _IOWR('i',17, struct ifreq)     /* get ifnet flags */
+#define        OSIOCGIFBRDADDR _IOWR('i',18, struct ifreq)     /* get broadcast addr */
+#define        SIOCGIFBRDADDR  _IOWR('i',35, struct ifreq)     /* get broadcast addr */
+#define        SIOCSIFBRDADDR  _IOW('i',19, struct ifreq)      /* set broadcast addr */
+#define        OSIOCGIFCONF    _IOWR('i',20, struct ifconf)    /* get ifnet list */
+#define        SIOCGIFCONF     _IOWR('i',36, struct ifconf)    /* get ifnet list */
+#define        OSIOCGIFNETMASK _IOWR('i',21, struct ifreq)     /* get net addr mask */
+#define        SIOCGIFNETMASK  _IOWR('i',37, struct ifreq)     /* get net addr mask */
+#define        SIOCSIFNETMASK  _IOW('i',22, struct ifreq)      /* set net addr mask */
+#define        SIOCGIFMETRIC   _IOWR('i',23, struct ifreq)     /* get IF metric */
+#define        SIOCSIFMETRIC   _IOW('i',24, struct ifreq)      /* set IF metric */
+#define        SIOCDIFADDR     _IOW('i',25, struct ifreq)      /* delete IF addr */
+#define        SIOCAIFADDR     _IOW('i',26, struct ifaliasreq) /* add/chg IF alias */
+
+#define        SIOCSARP        _IOW('i', 30, struct arpreq)    /* set arp entry */
+#define        OSIOCGARP       _IOWR('i',31, struct arpreq)    /* get arp entry */
+#define        SIOCGARP        _IOWR('i',38, struct arpreq)    /* get arp entry */
+#define        SIOCDARP        _IOW('i', 32, struct arpreq)    /* delete arp entry */
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    ioctl __P((int, unsigned long, ...));
+__END_DECLS
+
+#endif /* !KERNEL */
+
+#endif /* !_IOCTL_H_ */
+
+/* - note: keep outside _IOCTL_H_
+ * Compatability with old terminal driver
+ *
+ * Source level -> #define USE_OLD_TTY
+ * Kernel level -> options COMPAT_43
+ */
+#if defined(USE_OLD_TTY) || defined(COMPAT_43)
+#ifdef KERNEL
+#include "ioctl_compat.h"
+#else
+#include <sys/ioctl_compat.h>
+#endif
+#endif
diff --git a/usr/src/sys.386bsd/sys/ioctl_compat.h b/usr/src/sys.386bsd/sys/ioctl_compat.h
new file mode 100644 (file)
index 0000000..7762049
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ioctl_compat.h      7.4 (Berkeley) 2/5/91
+ */
+
+#ifndef _IOCTL_COMPAT_H_
+#define        _IOCTL_COMPAT_H_
+
+#ifdef KERNEL
+#include "ttychars.h"
+#include "ttydev.h"
+#else
+#include <sys/ttychars.h>
+#include <sys/ttydev.h>
+#endif
+
+struct tchars {
+       char    t_intrc;        /* interrupt */
+       char    t_quitc;        /* quit */
+       char    t_startc;       /* start output */
+       char    t_stopc;        /* stop output */
+       char    t_eofc;         /* end-of-file */
+       char    t_brkc;         /* input delimiter (like nl) */
+};
+
+struct ltchars {
+       char    t_suspc;        /* stop process signal */
+       char    t_dsuspc;       /* delayed stop process signal */
+       char    t_rprntc;       /* reprint line */
+       char    t_flushc;       /* flush output (toggles) */
+       char    t_werasc;       /* word erase */
+       char    t_lnextc;       /* literal next character */
+};
+
+/*
+ * Structure for TIOCGETP and TIOCSETP ioctls.
+ */
+#ifndef _SGTTYB_
+#define        _SGTTYB_
+struct sgttyb {
+       char    sg_ispeed;              /* input speed */
+       char    sg_ospeed;              /* output speed */
+       char    sg_erase;               /* erase character */
+       char    sg_kill;                /* kill character */
+       short   sg_flags;               /* mode flags */
+};
+#endif
+
+#ifdef USE_OLD_TTY
+# undef  TIOCGETD
+# define TIOCGETD      _IOR('t', 0, int)       /* get line discipline */
+# undef  TIOCSETD
+# define TIOCSETD      _IOW('t', 1, int)       /* set line discipline */
+#else
+# define OTIOCGETD     _IOR('t', 0, int)       /* get line discipline */
+# define OTIOCSETD     _IOW('t', 1, int)       /* set line discipline */
+#endif
+#define        TIOCHPCL        _IO('t', 2)             /* hang up on last close */
+#define        TIOCGETP        _IOR('t', 8,struct sgttyb)/* get parameters -- gtty */
+#define        TIOCSETP        _IOW('t', 9,struct sgttyb)/* set parameters -- stty */
+#define        TIOCSETN        _IOW('t',10,struct sgttyb)/* as above, but no flushtty*/
+#define        TIOCSETC        _IOW('t',17,struct tchars)/* set special characters */
+#define        TIOCGETC        _IOR('t',18,struct tchars)/* get special characters */
+#define                TANDEM          0x00000001      /* send stopc on out q full */
+#define                CBREAK          0x00000002      /* half-cooked mode */
+#define                LCASE           0x00000004      /* simulate lower case */
+#define                ECHO            0x00000008      /* echo input */
+#define                CRMOD           0x00000010      /* map \r to \r\n on output */
+#define                RAW             0x00000020      /* no i/o processing */
+#define                ODDP            0x00000040      /* get/send odd parity */
+#define                EVENP           0x00000080      /* get/send even parity */
+#define                ANYP            0x000000c0      /* get any parity/send none */
+#define                NLDELAY         0x00000300      /* \n delay */
+#define                        NL0     0x00000000
+#define                        NL1     0x00000100      /* tty 37 */
+#define                        NL2     0x00000200      /* vt05 */
+#define                        NL3     0x00000300
+#define                TBDELAY         0x00000c00      /* horizontal tab delay */
+#define                        TAB0    0x00000000
+#define                        TAB1    0x00000400      /* tty 37 */
+#define                        TAB2    0x00000800
+#define                XTABS           0x00000c00      /* expand tabs on output */
+#define                CRDELAY         0x00003000      /* \r delay */
+#define                        CR0     0x00000000
+#define                        CR1     0x00001000      /* tn 300 */
+#define                        CR2     0x00002000      /* tty 37 */
+#define                        CR3     0x00003000      /* concept 100 */
+#define                VTDELAY         0x00004000      /* vertical tab delay */
+#define                        FF0     0x00000000
+#define                        FF1     0x00004000      /* tty 37 */
+#define                BSDELAY         0x00008000      /* \b delay */
+#define                        BS0     0x00000000
+#define                        BS1     0x00008000
+#define                ALLDELAY        (NLDELAY|TBDELAY|CRDELAY|VTDELAY|BSDELAY)
+#define                CRTBS           0x00010000      /* do backspacing for crt */
+#define                PRTERA          0x00020000      /* \ ... / erase */
+#define                CRTERA          0x00040000      /* " \b " to wipe out char */
+#define                TILDE           0x00080000      /* hazeltine tilde kludge */
+#define                MDMBUF          0x00100000      /*start/stop output on carrier*/
+#define                LITOUT          0x00200000      /* literal output */
+#define                TOSTOP          0x00400000      /*SIGSTOP on background output*/
+#define                FLUSHO          0x00800000      /* flush output to terminal */
+#define                NOHANG          0x01000000      /* (no-op) was no SIGHUP on carrier drop */
+#define                L001000         0x02000000
+#define                CRTKIL          0x04000000      /* kill line with " \b " */
+#define                PASS8           0x08000000
+#define                CTLECH          0x10000000      /* echo control chars as ^X */
+#define                PENDIN          0x20000000      /* tp->t_rawq needs reread */
+#define                DECCTQ          0x40000000      /* only ^Q starts after ^S */
+#define                NOFLSH          0x80000000      /* no output flush on signal */
+#define        TIOCLBIS        _IOW('t', 127, int)     /* bis local mode bits */
+#define        TIOCLBIC        _IOW('t', 126, int)     /* bic local mode bits */
+#define        TIOCLSET        _IOW('t', 125, int)     /* set entire local mode word */
+#define        TIOCLGET        _IOR('t', 124, int)     /* get local modes */
+#define                LCRTBS          (CRTBS>>16)
+#define                LPRTERA         (PRTERA>>16)
+#define                LCRTERA         (CRTERA>>16)
+#define                LTILDE          (TILDE>>16)
+#define                LMDMBUF         (MDMBUF>>16)
+#define                LLITOUT         (LITOUT>>16)
+#define                LTOSTOP         (TOSTOP>>16)
+#define                LFLUSHO         (FLUSHO>>16)
+#define                LNOHANG         (NOHANG>>16)
+#define                LCRTKIL         (CRTKIL>>16)
+#define                LPASS8          (PASS8>>16)
+#define                LCTLECH         (CTLECH>>16)
+#define                LPENDIN         (PENDIN>>16)
+#define                LDECCTQ         (DECCTQ>>16)
+#define                LNOFLSH         (NOFLSH>>16)
+#define        TIOCSLTC        _IOW('t',117,struct ltchars)/* set local special chars*/
+#define        TIOCGLTC        _IOR('t',116,struct ltchars)/* get local special chars*/
+#define OTIOCCONS      _IO('t', 98)    /* for hp300 -- sans int arg */
+#define        OTTYDISC        0
+#define        NETLDISC        1
+#define        NTTYDISC        2
+
+#endif /* !_IOCTL_COMPAT_H_ */
diff --git a/usr/src/sys.386bsd/sys/ipc.h b/usr/src/sys.386bsd/sys/ipc.h
new file mode 100644 (file)
index 0000000..d72a765
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ipc.h       7.2 (Berkeley) 2/5/91
+ */
+
+/*
+ * SVID compatible ipc.h file
+ */
+#ifndef _IPC_H_
+#define _IPC_H_
+
+typedef        long    key_t;  /* XXX should be in types.h */
+
+struct ipc_perm {
+       ushort  cuid;   /* creator user id */
+       ushort  cgid;   /* creator group id */
+       ushort  uid;    /* user id */
+       ushort  gid;    /* group id */
+       ushort  mode;   /* r/w permission */
+       ushort  seq;    /* sequence # (to generate unique msg/sem/shm id) */
+       key_t   key;    /* user specified msg/sem/shm key */
+};
+
+/* common mode bits */
+#define        IPC_R           00400   /* read permission */
+#define        IPC_W           00200   /* write/alter permission */
+
+/* SVID required constants (same values as system 5) */
+#define        IPC_CREAT       01000   /* create entry if key does not exist */
+#define        IPC_EXCL        02000   /* fail if key exists */
+#define        IPC_NOWAIT      04000   /* error if request must wait */
+
+#define        IPC_PRIVATE     (key_t)0 /* private key */
+
+#define        IPC_RMID        0       /* remove identifier */
+#define        IPC_SET         1       /* set options */
+#define        IPC_STAT        2       /* get options */
+
+#endif /* !_IPC_H_ */
diff --git a/usr/src/sys.386bsd/sys/kernel.h b/usr/src/sys.386bsd/sys/kernel.h
new file mode 100644 (file)
index 0000000..fe778ed
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kernel.h    7.4 (Berkeley) 2/15/91
+ */
+
+/* Global variables for the kernel. */
+long rmalloc();
+
+/* 1.1 */
+long hostid;
+char hostname[MAXHOSTNAMELEN];
+int hostnamelen;
+
+/* 1.2 */
+struct timeval boottime;
+struct timeval time;
+struct timezone tz;                    /* XXX */
+
+int hz;                                        /* clock frequency */
+int phz;                               /* alternate clock's frequency */
+int tick;
+int lbolt;                             /* once a second sleep address */
+int realitexpire();
+
+fixpt_t        averunnable[3];
+#if defined(COMPAT_43) && (defined(vax) || defined(tahoe))
+double avenrun[3];
+#endif /* COMPAT_43 */
+
+#ifdef GPROF
+u_long s_textsize;
+int profiling;
+u_short *kcount;
+char *s_lowpc;
+#endif
diff --git a/usr/src/sys.386bsd/sys/kinfo.h b/usr/src/sys.386bsd/sys/kinfo.h
new file mode 100644 (file)
index 0000000..c4a155c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kinfo.h     7.9 (Berkeley) 6/26/91
+ */
+
+/*
+ * Get kernel info
+ */
+#define ki_op(x)               ((x)&0x0000ffff)
+#define ki_type(x)             ((x)&0x0000ff00)
+
+/* 
+ * proc info 
+ */
+#define        KINFO_PROC              (0<<8)
+#define KINFO_PROC_ALL (KINFO_PROC|0)  /* everything */
+#define        KINFO_PROC_PID  (KINFO_PROC|1)  /* by process id */
+#define        KINFO_PROC_PGRP (KINFO_PROC|2)  /* by process group id */
+#define        KINFO_PROC_SESSION (KINFO_PROC|3)       /* by session of pid */
+#define        KINFO_PROC_TTY  (KINFO_PROC|4)  /* by controlling tty */
+#define        KINFO_PROC_UID  (KINFO_PROC|5)  /* by effective uid */
+#define        KINFO_PROC_RUID (KINFO_PROC|6)  /* by real uid */
+
+/*
+ * Routing table
+ */
+#define ki_af(x)               (((x)&0x00ff0000) >> 16)
+#define KINFO_RT               (1<<8)
+#define KINFO_RT_DUMP  (KINFO_RT|1)    /* dump; may limit to a.f. */
+#define KINFO_RT_FLAGS (KINFO_RT|2)    /* by flags, e.g. RESOLVING */
+
+/*
+ * vnodes
+ */
+#define        KINFO_VNODE             (2<<8)
+
+/*
+ * file structures
+ */
+#define KINFO_FILE             (3<<8)
+
+/*
+ * Locking and stats
+ */
+
+struct kinfo_lock {
+       int     kl_lock;
+       int     kl_want;
+       int     kl_locked;
+};
+
+#ifdef KERNEL
+extern struct kinfo_lock kinfo_lock;
+#else
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    getkerninfo __P((int, void *, int *, int));
+__END_DECLS
+#endif
diff --git a/usr/src/sys.386bsd/sys/kinfo_proc.h b/usr/src/sys.386bsd/sys/kinfo_proc.h
new file mode 100644 (file)
index 0000000..28b2c17
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kinfo_proc.h        7.1 (Berkeley) 5/9/91
+ */
+
+#ifndef _KINFO_PROC_H_
+#define        _KINFO_PROC_H_
+
+#ifndef KERNEL
+#include <sys/time.h>
+#include <sys/ucred.h>
+#include <sys/proc.h>
+#include <vm/vm.h>
+#endif
+
+/* 
+ * getkerninfo() proc ops return arrays of augmented proc structures:
+ */
+struct kinfo_proc {
+       struct  proc kp_proc;                   /* proc structure */
+       struct  eproc {
+               struct  proc *e_paddr;          /* address of proc */
+               struct  session *e_sess;        /* session pointer */
+               struct  pcred e_pcred;          /* process credentials */
+               struct  ucred e_ucred;          /* current credentials */
+               struct  vmspace e_vm;           /* address space */
+               pid_t   e_ppid;                 /* parent process id */
+               pid_t   e_pgid;                 /* process group id */
+               short   e_jobc;                 /* job control counter */
+               dev_t   e_tdev;                 /* controlling tty dev */
+               pid_t   e_tpgid;                /* tty process group id */
+               struct  session *e_tsess;       /* tty session pointer */
+#define        WMESGLEN        7
+               char    e_wmesg[WMESGLEN+1];    /* wchan message */
+               segsz_t e_xsize;                /* text size */
+               short   e_xrssize;              /* text rss */
+               short   e_xccount;              /* text references */
+               short   e_xswrss;
+               long    e_flag;
+#define        EPROC_CTTY      0x01    /* controlling tty vnode active */
+#define        EPROC_SLEADER   0x02    /* session leader */
+               char    e_login[MAXLOGNAME];    /* setlogin() name */
+               long    e_spare[4];
+       } kp_eproc;
+};
+
+#ifdef KERNEL
+void   fill_eproc __P((struct proc *, struct eproc *));
+#endif
+
+#endif /* !_KINFO_PROC_H_ */
diff --git a/usr/src/sys.386bsd/sys/ktrace.h b/usr/src/sys.386bsd/sys/ktrace.h
new file mode 100644 (file)
index 0000000..9f63359
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ktrace.h    7.4 (Berkeley) 5/7/91
+ */
+
+/*
+ * operations to ktrace system call  (KTROP(op))
+ */
+#define KTROP_SET              0       /* set trace points */
+#define KTROP_CLEAR            1       /* clear trace points */
+#define KTROP_CLEARFILE                2       /* stop all tracing to file */
+#define        KTROP(o)                ((o)&3) /* macro to extract operation */
+/*
+ * flags (ORed in with operation)
+ */
+#define KTRFLAG_DESCEND                4       /* perform op on all children too */
+
+/*
+ * ktrace record header
+ */
+struct ktr_header {
+       int     ktr_len;                /* length of buf */
+       short   ktr_type;               /* trace record type */
+       pid_t   ktr_pid;                /* process id */
+       char    ktr_comm[MAXCOMLEN+1];  /* command name */
+       struct  timeval ktr_time;       /* timestamp */
+       caddr_t ktr_buf;
+};
+
+/*
+ * Test for kernel trace point
+ */
+#define KTRPOINT(p, type)      ((p)->p_traceflag & (1<<(type)))
+
+/*
+ * ktrace record types
+ */
+
+/*
+ * KTR_SYSCALL - system call record
+ */
+#define KTR_SYSCALL    1
+struct ktr_syscall {
+       short   ktr_code;               /* syscall number */
+       short   ktr_narg;               /* number of arguments */
+       /*
+        * followed by ktr_narg ints
+        */
+};
+
+/*
+ * KTR_SYSRET - return from system call record
+ */
+#define KTR_SYSRET     2
+struct ktr_sysret {
+       short   ktr_code;
+       short   ktr_eosys;
+       int     ktr_error;
+       int     ktr_retval;
+};
+
+/*
+ * KTR_NAMEI - namei record
+ */
+#define KTR_NAMEI      3
+       /* record contains pathname */
+
+/*
+ * KTR_GENIO - trace generic process i/o
+ */
+#define KTR_GENIO      4
+struct ktr_genio {
+       int     ktr_fd;
+       enum    uio_rw ktr_rw;
+       /*
+        * followed by data successfully read/written
+        */
+};
+
+/*
+ * KTR_PSIG - trace processed signal
+ */
+#define        KTR_PSIG        5
+struct ktr_psig {
+       int     signo;
+       sig_t   action;
+       int     mask;
+       int     code;
+};
+
+/*
+ * kernel trace points (in p_traceflag)
+ */
+#define KTRFAC_MASK    0x00ffffff
+#define KTRFAC_SYSCALL (1<<KTR_SYSCALL)
+#define KTRFAC_SYSRET  (1<<KTR_SYSRET)
+#define KTRFAC_NAMEI   (1<<KTR_NAMEI)
+#define KTRFAC_GENIO   (1<<KTR_GENIO)
+#define        KTRFAC_PSIG     (1<<KTR_PSIG)
+/*
+ * trace flags (also in p_traceflags)
+ */
+#define KTRFAC_ROOT    0x80000000      /* root set this trace */
+#define KTRFAC_INHERIT 0x40000000      /* pass trace flags to children */
+
+#ifndef        KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    ktrace __P((const char *, int, int, pid_t));
+__END_DECLS
+
+#endif /* !KERNEL */
diff --git a/usr/src/sys.386bsd/sys/malloc.h b/usr/src/sys.386bsd/sys/malloc.h
new file mode 100644 (file)
index 0000000..08e7be4
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)malloc.h    7.25 (Berkeley) 5/15/91
+ */
+
+#ifndef _MALLOC_H_
+#define        _MALLOC_H_
+
+#define KMEMSTATS
+
+/*
+ * flags to malloc
+ */
+#define        M_WAITOK        0x0000
+#define        M_NOWAIT        0x0001
+
+/*
+ * Types of memory to be allocated
+ */
+#define        M_FREE          0       /* should be on free list */
+#define        M_MBUF          1       /* mbuf */
+#define        M_DEVBUF        2       /* device driver memory */
+#define        M_SOCKET        3       /* socket structure */
+#define        M_PCB           4       /* protocol control block */
+#define        M_RTABLE        5       /* routing tables */
+#define        M_HTABLE        6       /* IMP host tables */
+#define        M_FTABLE        7       /* fragment reassembly header */
+#define        M_ZOMBIE        8       /* zombie proc status */
+#define        M_IFADDR        9       /* interface address */
+#define        M_SOOPTS        10      /* socket options */
+#define        M_SONAME        11      /* socket name */
+#define        M_NAMEI         12      /* namei path name buffer */
+#define        M_GPROF         13      /* kernel profiling buffer */
+#define        M_IOCTLOPS      14      /* ioctl data buffer */
+#define        M_SUPERBLK      15      /* super block data */
+#define        M_CRED          16      /* credentials */
+#define        M_PGRP          17      /* process group header */
+#define        M_SESSION       18      /* session header */
+#define        M_IOV           19      /* large iov's */
+#define        M_MOUNT         20      /* vfs mount struct */
+#define        M_FHANDLE       21      /* network file handle */
+#define        M_NFSREQ        22      /* NFS request header */
+#define        M_NFSMNT        23      /* NFS mount structure */
+#define        M_VNODE         24      /* Dynamically allocated vnodes */
+#define        M_CACHE         25      /* Dynamically allocated cache entries */
+#define        M_DQUOT         26      /* UFS quota entries */
+#define        M_UFSMNT        27      /* UFS mount structure */
+#define        M_MAPMEM        28      /* mapped memory descriptors */
+#define        M_SHM           29      /* SVID compatible shared memory segments */
+#define        M_VMMAP         30      /* VM map structures */
+#define        M_VMMAPENT      31      /* VM map entry structures */
+#define        M_VMOBJ         32      /* VM object structure */
+#define        M_VMOBJHASH     33      /* VM object hash structure */
+#define        M_VMPMAP        34      /* VM pmap */
+#define        M_VMPVENT       35      /* VM phys-virt mapping entry */
+#define        M_VMPAGER       36      /* XXX: VM pager struct */
+#define        M_VMPGDATA      37      /* XXX: VM pager private data */
+#define        M_FILE          38      /* Open file structure */
+#define        M_FILEDESC      39      /* Open file descriptor table */
+#define        M_LOCKF         40      /* Byte-range locking structures */
+#define        M_PROC          41      /* Proc structures */
+#define        M_SUBPROC       42      /* Proc sub-structures */
+#define        M_TEMP          49      /* misc temporary data buffers */
+#define        M_LAST          50
+
+#define INITKMEMNAMES { \
+       "free",         /* 0 M_FREE */ \
+       "mbuf",         /* 1 M_MBUF */ \
+       "devbuf",       /* 2 M_DEVBUF */ \
+       "socket",       /* 3 M_SOCKET */ \
+       "pcb",          /* 4 M_PCB */ \
+       "routetbl",     /* 5 M_RTABLE */ \
+       "hosttbl",      /* 6 M_HTABLE */ \
+       "fragtbl",      /* 7 M_FTABLE */ \
+       "zombie",       /* 8 M_ZOMBIE */ \
+       "ifaddr",       /* 9 M_IFADDR */ \
+       "soopts",       /* 10 M_SOOPTS */ \
+       "soname",       /* 11 M_SONAME */ \
+       "namei",        /* 12 M_NAMEI */ \
+       "gprof",        /* 13 M_GPROF */ \
+       "ioctlops",     /* 14 M_IOCTLOPS */ \
+       "superblk",     /* 15 M_SUPERBLK */ \
+       "cred",         /* 16 M_CRED */ \
+       "pgrp",         /* 17 M_PGRP */ \
+       "session",      /* 18 M_SESSION */ \
+       "iov",          /* 19 M_IOV */ \
+       "mount",        /* 20 M_MOUNT */ \
+       "fhandle",      /* 21 M_FHANDLE */ \
+       "NFS req",      /* 22 M_NFSREQ */ \
+       "NFS mount",    /* 23 M_NFSMNT */ \
+       "vnodes",       /* 24 M_VNODE */ \
+       "namecache",    /* 25 M_CACHE */ \
+       "UFS quota",    /* 26 M_DQUOT */ \
+       "UFS mount",    /* 27 M_UFSMNT */ \
+       "mapmem",       /* 28 M_MAPMEM */ \
+       "shm",          /* 29 M_SHM */ \
+       "VM map",       /* 30 M_VMMAP */ \
+       "VM mapent",    /* 31 M_VMMAPENT */ \
+       "VM object",    /* 32 M_VMOBJ */ \
+       "VM objhash",   /* 33 M_VMOBJHASH */ \
+       "VM pmap",      /* 34 M_VMPMAP */ \
+       "VM pvmap",     /* 35 M_VMPVENT */ \
+       "VM pager",     /* 36 M_VMPAGER */ \
+       "VM pgdata",    /* 37 M_VMPGDATA */ \
+       "file",         /* 38 M_FILE */ \
+       "file desc",    /* 39 M_FILEDESC */ \
+       "lockf",        /* 40 M_LOCKF */ \
+       "proc",         /* 41 M_PROC */ \
+       "subproc",      /* 42 M_PROC */ \
+       0, 0, 0, 0, 0, 0, \
+       "temp",         /* 49 M_TEMP */ \
+}
+
+struct kmemstats {
+       long    ks_inuse;       /* # of packets of this type currently in use */
+       long    ks_calls;       /* total packets of this type ever allocated */
+       long    ks_memuse;      /* total memory held in bytes */
+       u_short ks_limblocks;   /* number of times blocked for hitting limit */
+       u_short ks_mapblocks;   /* number of times blocked for kernel map */
+       long    ks_maxused;     /* maximum number ever used */
+       long    ks_limit;       /* most that are allowed to exist */
+};
+
+/*
+ * Array of descriptors that describe the contents of each page
+ */
+struct kmemusage {
+       short ku_indx;          /* bucket index */
+       union {
+               u_short freecnt;/* for small allocations, free pieces in page */
+               u_short pagecnt;/* for large allocations, pages alloced */
+       } ku_un;
+};
+#define ku_freecnt ku_un.freecnt
+#define ku_pagecnt ku_un.pagecnt
+
+/*
+ * Set of buckets for each size of memory block that is retained
+ */
+struct kmembuckets {
+       caddr_t kb_next;        /* list of free blocks */
+       long    kb_calls;       /* total calls to allocate this size */
+       long    kb_total;       /* total number of blocks allocated */
+       long    kb_totalfree;   /* # of free elements in this bucket */
+       long    kb_elmpercl;    /* # of elements in this sized allocation */
+       long    kb_highwat;     /* high water mark */
+       long    kb_couldfree;   /* over high water mark and could free */
+};
+
+#ifdef KERNEL
+#define        MINALLOCSIZE    (1 << MINBUCKET)
+#define BUCKETINDX(size) \
+       (size) <= (MINALLOCSIZE * 128) \
+               ? (size) <= (MINALLOCSIZE * 8) \
+                       ? (size) <= (MINALLOCSIZE * 2) \
+                               ? (size) <= (MINALLOCSIZE * 1) \
+                                       ? (MINBUCKET + 0) \
+                                       : (MINBUCKET + 1) \
+                               : (size) <= (MINALLOCSIZE * 4) \
+                                       ? (MINBUCKET + 2) \
+                                       : (MINBUCKET + 3) \
+                       : (size) <= (MINALLOCSIZE* 32) \
+                               ? (size) <= (MINALLOCSIZE * 16) \
+                                       ? (MINBUCKET + 4) \
+                                       : (MINBUCKET + 5) \
+                               : (size) <= (MINALLOCSIZE * 64) \
+                                       ? (MINBUCKET + 6) \
+                                       : (MINBUCKET + 7) \
+               : (size) <= (MINALLOCSIZE * 2048) \
+                       ? (size) <= (MINALLOCSIZE * 512) \
+                               ? (size) <= (MINALLOCSIZE * 256) \
+                                       ? (MINBUCKET + 8) \
+                                       : (MINBUCKET + 9) \
+                               : (size) <= (MINALLOCSIZE * 1024) \
+                                       ? (MINBUCKET + 10) \
+                                       : (MINBUCKET + 11) \
+                       : (size) <= (MINALLOCSIZE * 8192) \
+                               ? (size) <= (MINALLOCSIZE * 4096) \
+                                       ? (MINBUCKET + 12) \
+                                       : (MINBUCKET + 13) \
+                               : (size) <= (MINALLOCSIZE * 16384) \
+                                       ? (MINBUCKET + 14) \
+                                       : (MINBUCKET + 15)
+
+/*
+ * Turn virtual addresses into kmem map indicies
+ */
+#define kmemxtob(alloc)        (kmembase + (alloc) * NBPG)
+#define btokmemx(addr) (((caddr_t)(addr) - kmembase) / NBPG)
+#define btokup(addr)   (&kmemusage[((caddr_t)(addr) - kmembase) >> CLSHIFT])
+
+/*
+ * Macro versions for the usual cases of malloc/free
+ */
+#ifdef KMEMSTATS
+#define        MALLOC(space, cast, size, type, flags) \
+       (space) = (cast)malloc((u_long)(size), type, flags)
+#define FREE(addr, type) free((caddr_t)(addr), type)
+
+#else /* do not collect statistics */
+#define        MALLOC(space, cast, size, type, flags) { \
+       register struct kmembuckets *kbp = &bucket[BUCKETINDX(size)]; \
+       long s = splimp(); \
+       if (kbp->kb_next == NULL) { \
+               (space) = (cast)malloc((u_long)(size), type, flags); \
+       } else { \
+               (space) = (cast)kbp->kb_next; \
+               kbp->kb_next = *(caddr_t *)(space); \
+       } \
+       splx(s); \
+}
+
+#define FREE(addr, type) { \
+       register struct kmembuckets *kbp; \
+       register struct kmemusage *kup = btokup(addr); \
+       long s = splimp(); \
+       if (1 << kup->ku_indx > MAXALLOCSAVE) { \
+               free((caddr_t)(addr), type); \
+       } else { \
+               kbp = &bucket[kup->ku_indx]; \
+               *(caddr_t *)(addr) = kbp->kb_next; \
+               kbp->kb_next = (caddr_t)(addr); \
+       } \
+       splx(s); \
+}
+#endif /* do not collect statistics */
+
+extern struct kmemstats kmemstats[];
+extern struct kmemusage *kmemusage;
+extern char *kmembase;
+extern struct kmembuckets bucket[];
+extern void *malloc __P((unsigned long size, int type, int flags));
+extern void free __P((void *addr, int type));
+#endif /* KERNEL */
+#endif /* !_MALLOC_H_ */
diff --git a/usr/src/sys.386bsd/sys/mapmem.h b/usr/src/sys.386bsd/sys/mapmem.h
new file mode 100644 (file)
index 0000000..654eb32
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: mmap.h 1.4 89/08/14$
+ *
+ *     @(#)mapmem.h    7.2 (Berkeley) 6/6/90
+ */
+
+/*
+ * Mapped memory descriptors.
+ *
+ * A process has one of these for every "mapped" memory region.
+ * Mapped memory is characterized by:
+ *     - Corresponding physical memory is neither paged nor swapped.
+ *     - User PTEs have both pg_v and pg_fod set.
+ *     - Has no backing swap space unless mapped over existing data.
+ *     - If mapped over existing data, original data is lost when
+ *       segment is unmapped. (i.e. pages are reinitialized to ZFOD)
+ * Operations:
+ *     (*mm_fork)(mp, ischild) struct mapmem *mp; int ischild;
+ *             Called during fork in both parent and child.  Parent
+ *             call can be used for maintaining reference counts and
+ *             should NEVER destroy the region.  Child call should be
+ *             used for unmapping regions not inherited across forks.
+ *     (*mm_vfork)(mp, fup, tup) struct mapmem *mp; struct user *fup, *tup;
+ *             Called twice during vfork (always in parent context)
+ *             after exchanging resources (including u_mmap chains).
+ *             `fup' is the donor and `tup' the recipient of the
+ *             "parent" (full) context.  Needed for maintaining
+ *             reference counts or if the underlying object contains
+ *             references to owning process.  Routine should NEVER
+ *             destroy the region.
+ *     (*mm_exec)(mp) struct mapmem *mp;
+ *             Called during exec before releasing old address space.
+ *             Used for graceful cleanup of underlying object.  Resources
+ *             will be freed regardless of what this routine does.
+ *             Need to add a post-exec call to re-establish mappings
+ *             in the new address space for regions inherited across execs.
+ *     (*mm_exit)(mp) struct mapmem *mp;
+ *             Called during exit just before releasing address space.
+ *             Used for graceful cleanup of underlying object.  Resources
+ *             will be freed regardless of what this routine does.
+ * The default semantics for a region with routine addresses of zero are
+ * that it is inherited across forks, stays with the "active" process during
+ * vforks, and is destroyed by execs and exit.
+ */
+
+struct mapmem {
+       struct  mapmem *mm_next;        /* next descriptor */
+       int     mm_id;                  /* identifier (e.g. fd, shmid) */
+       caddr_t mm_uva;                 /* user VA at which region is mapped */
+       int     mm_size;                /* size of mapped region */
+       int     mm_prot;                /* attributes of region */
+       struct mapmemops {              /* operations */
+               int     (*mm_fork)();
+               int     (*mm_vfork)();
+               int     (*mm_exec)();
+               int     (*mm_exit)();
+       } *mm_ops;
+};
+
+#define MMNIL  ((struct mapmem *)0)
+
+/* attributes */
+#define MM_RW          0x00    /* region is read-write */
+#define        MM_RO           0x01    /* region is read-only */
+#define MM_CI          0x02    /* caching is inhibited on region */
+#define MM_NOCORE      0x04    /* cannot write region to core file;
+                                  e.g. mapped framebuffer hardware */
+
+#ifdef KERNEL
+#define MMALLOC(mp) \
+       (mp) = (struct mapmem *)malloc((u_long)sizeof(struct mapmem), \
+           M_MAPMEM, M_WAITOK)
+
+#define MMFREE(mp) \
+       free((caddr_t)(mp), M_MAPMEM)
+#endif
diff --git a/usr/src/sys.386bsd/sys/mbuf.h b/usr/src/sys.386bsd/sys/mbuf.h
new file mode 100644 (file)
index 0000000..290b917
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mbuf.h      7.14 (Berkeley) 12/5/90
+ */
+
+#ifndef M_WAITOK
+#include "malloc.h"
+#endif
+
+/*
+ * Mbufs are of a single size, MSIZE (machine/machparam.h), which
+ * includes overhead.  An mbuf may add a single "mbuf cluster" of size
+ * MCLBYTES (also in machine/machparam.h), which has no additional overhead
+ * and is used instead of the internal data area; this is done when
+ * at least MINCLSIZE of data must be stored.
+ */
+
+#define        MLEN            (MSIZE - sizeof(struct m_hdr))  /* normal data len */
+#define        MHLEN           (MLEN - sizeof(struct pkthdr))  /* data len w/pkthdr */
+
+#define        MINCLSIZE       (MHLEN + MLEN)  /* smallest amount to put in cluster */
+#define        M_MAXCOMPRESS   (MHLEN / 2)     /* max amount to copy for compression */
+
+/*
+ * Macros for type conversion
+ * mtod(m,t) - convert mbuf pointer to data pointer of correct type
+ * dtom(x) -   convert data pointer within mbuf to mbuf pointer (XXX)
+ * mtocl(x) -  convert pointer within cluster to cluster index #
+ * cltom(x) -  convert cluster # to ptr to beginning of cluster
+ */
+#define mtod(m,t)      ((t)((m)->m_data))
+#define        dtom(x)         ((struct mbuf *)((int)(x) & ~(MSIZE-1)))
+#define        mtocl(x)        (((u_int)(x) - (u_int)mbutl) >> MCLSHIFT)
+#define        cltom(x)        ((caddr_t)((u_int)mbutl + ((u_int)(x) >> MCLSHIFT)))
+
+/* header at beginning of each mbuf: */
+struct m_hdr {
+       struct  mbuf *mh_next;          /* next buffer in chain */
+       struct  mbuf *mh_nextpkt;       /* next chain in queue/record */
+       int     mh_len;                 /* amount of data in this mbuf */
+       caddr_t mh_data;                /* location of data */
+       short   mh_type;                /* type of data in this mbuf */
+       short   mh_flags;               /* flags; see below */
+};
+
+/* record/packet header in first mbuf of chain; valid if M_PKTHDR set */
+struct pkthdr {
+       int     len;            /* total packet length */
+       struct  ifnet *rcvif;   /* rcv interface */
+};
+
+/* description of external storage mapped into mbuf, valid if M_EXT set */
+struct m_ext {
+       caddr_t ext_buf;                /* start of buffer */
+       void    (*ext_free)();          /* free routine if not the usual */
+       u_int   ext_size;               /* size of buffer, for ext_free */
+};
+
+struct mbuf {
+       struct  m_hdr m_hdr;
+       union {
+               struct {
+                       struct  pkthdr MH_pkthdr;       /* M_PKTHDR set */
+                       union {
+                               struct  m_ext MH_ext;   /* M_EXT set */
+                               char    MH_databuf[MHLEN];
+                       } MH_dat;
+               } MH;
+               char    M_databuf[MLEN];                /* !M_PKTHDR, !M_EXT */
+       } M_dat;
+};
+#define        m_next          m_hdr.mh_next
+#define        m_len           m_hdr.mh_len
+#define        m_data          m_hdr.mh_data
+#define        m_type          m_hdr.mh_type
+#define        m_flags         m_hdr.mh_flags
+#define        m_nextpkt       m_hdr.mh_nextpkt
+#define        m_act           m_nextpkt
+#define        m_pkthdr        M_dat.MH.MH_pkthdr
+#define        m_ext           M_dat.MH.MH_dat.MH_ext
+#define        m_pktdat        M_dat.MH.MH_dat.MH_databuf
+#define        m_dat           M_dat.M_databuf
+
+/* mbuf flags */
+#define        M_EXT           0x0001  /* has associated external storage */
+#define        M_PKTHDR        0x0002  /* start of record */
+#define        M_EOR           0x0004  /* end of record */
+
+/* mbuf pkthdr flags, also in m_flags */
+#define        M_BCAST         0x0100  /* send/received as link-level broadcast */
+#define        M_MCAST         0x0200  /* send/received as link-level multicast */
+
+/* flags copied when copying m_pkthdr */
+#define        M_COPYFLAGS     (M_PKTHDR|M_EOR|M_BCAST|M_MCAST)
+
+/* mbuf types */
+#define        MT_FREE         0       /* should be on free list */
+#define        MT_DATA         1       /* dynamic (data) allocation */
+#define        MT_HEADER       2       /* packet header */
+#define        MT_SOCKET       3       /* socket structure */
+#define        MT_PCB          4       /* protocol control block */
+#define        MT_RTABLE       5       /* routing tables */
+#define        MT_HTABLE       6       /* IMP host tables */
+#define        MT_ATABLE       7       /* address resolution tables */
+#define        MT_SONAME       8       /* socket name */
+#define        MT_SOOPTS       10      /* socket options */
+#define        MT_FTABLE       11      /* fragment reassembly header */
+#define        MT_RIGHTS       12      /* access rights */
+#define        MT_IFADDR       13      /* interface address */
+#define MT_CONTROL     14      /* extra-data protocol message */
+#define MT_OOBDATA     15      /* expedited data  */
+
+/* flags to m_get/MGET */
+#define        M_DONTWAIT      M_NOWAIT
+#define        M_WAIT          M_WAITOK
+
+/*
+ * mbuf allocation/deallocation macros:
+ *
+ *     MGET(struct mbuf *m, int how, int type)
+ * allocates an mbuf and initializes it to contain internal data.
+ *
+ *     MGETHDR(struct mbuf *m, int how, int type)
+ * allocates an mbuf and initializes it to contain a packet header
+ * and internal data.
+ */
+#define        MGET(m, how, type) { \
+       MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
+       if (m) { \
+               (m)->m_type = (type); \
+               mbstat.m_mtypes[type]++; \
+               (m)->m_next = (struct mbuf *)NULL; \
+               (m)->m_nextpkt = (struct mbuf *)NULL; \
+               (m)->m_data = (m)->m_dat; \
+               (m)->m_flags = 0; \
+       } else \
+               (m) = m_retry((how), (type)); \
+}
+
+#define        MGETHDR(m, how, type) { \
+       MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how)); \
+       if (m) { \
+               (m)->m_type = (type); \
+               mbstat.m_mtypes[type]++; \
+               (m)->m_next = (struct mbuf *)NULL; \
+               (m)->m_nextpkt = (struct mbuf *)NULL; \
+               (m)->m_data = (m)->m_pktdat; \
+               (m)->m_flags = M_PKTHDR; \
+       } else \
+               (m) = m_retryhdr((how), (type)); \
+}
+
+/*
+ * Mbuf cluster macros.
+ * MCLALLOC(caddr_t p, int how) allocates an mbuf cluster.
+ * MCLGET adds such clusters to a normal mbuf;
+ * the flag M_EXT is set upon success.
+ * MCLFREE releases a reference to a cluster allocated by MCLALLOC,
+ * freeing the cluster if the reference count has reached 0.
+ *
+ * Normal mbuf clusters are normally treated as character arrays
+ * after allocation, but use the first word of the buffer as a free list
+ * pointer while on the free list.
+ */
+union mcluster {
+       union   mcluster *mcl_next;
+       char    mcl_buf[MCLBYTES];
+};
+
+#define        MCLALLOC(p, how) \
+       { int ms = splimp(); \
+         if (mclfree == 0) \
+               (void)m_clalloc(1, (how)); \
+         if ((p) = (caddr_t)mclfree) { \
+               ++mclrefcnt[mtocl(p)]; \
+               mbstat.m_clfree--; \
+               mclfree = ((union mcluster *)(p))->mcl_next; \
+         } \
+         splx(ms); \
+       }
+
+#define        MCLGET(m, how) \
+       { MCLALLOC((m)->m_ext.ext_buf, (how)); \
+         if ((m)->m_ext.ext_buf != NULL) { \
+               (m)->m_data = (m)->m_ext.ext_buf; \
+               (m)->m_flags |= M_EXT; \
+               (m)->m_ext.ext_size = MCLBYTES;  \
+         } \
+       }
+
+#define        MCLFREE(p) \
+       { int ms = splimp(); \
+         if (--mclrefcnt[mtocl(p)] == 0) { \
+               ((union mcluster *)(p))->mcl_next = mclfree; \
+               mclfree = (union mcluster *)(p); \
+               mbstat.m_clfree++; \
+         } \
+         splx(ms); \
+       }
+
+/*
+ * MFREE(struct mbuf *m, struct mbuf *n)
+ * Free a single mbuf and associated external storage.
+ * Place the successor, if any, in n.
+ */
+#ifdef notyet
+#define        MFREE(m, n) \
+       { mbstat.m_mtypes[(m)->m_type]--; \
+         if ((m)->m_flags & M_EXT) { \
+               if ((m)->m_ext.ext_free) \
+                       (*((m)->m_ext.ext_free))((m)->m_ext.ext_buf, \
+                           (m)->m_ext.ext_size); \
+               else \
+                       MCLFREE((m)->m_ext.ext_buf); \
+         } \
+         (n) = (m)->m_next; \
+         FREE((m), mbtypes[(m)->m_type]); \
+       }
+#else /* notyet */
+#define        MFREE(m, nn) \
+       { mbstat.m_mtypes[(m)->m_type]--; \
+         if ((m)->m_flags & M_EXT) { \
+               MCLFREE((m)->m_ext.ext_buf); \
+         } \
+         (nn) = (m)->m_next; \
+         FREE((m), mbtypes[(m)->m_type]); \
+       }
+#endif
+
+/*
+ * Copy mbuf pkthdr from from to to.
+ * from must have M_PKTHDR set, and to must be empty.
+ */
+#define        M_COPY_PKTHDR(to, from) { \
+       (to)->m_pkthdr = (from)->m_pkthdr; \
+       (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \
+       (to)->m_data = (to)->m_pktdat; \
+}
+
+/*
+ * Set the m_data pointer of a newly-allocated mbuf (m_get/MGET) to place
+ * an object of the specified size at the end of the mbuf, longword aligned.
+ */
+#define        M_ALIGN(m, len) \
+       { (m)->m_data += (MLEN - (len)) &~ (sizeof(long) - 1); }
+/*
+ * As above, for mbufs allocated with m_gethdr/MGETHDR
+ * or initialized by M_COPY_PKTHDR.
+ */
+#define        MH_ALIGN(m, len) \
+       { (m)->m_data += (MHLEN - (len)) &~ (sizeof(long) - 1); }
+
+/*
+ * Compute the amount of space available
+ * before the current start of data in an mbuf.
+ */
+#define        M_LEADINGSPACE(m) \
+       ((m)->m_flags & M_EXT ? /* (m)->m_data - (m)->m_ext.ext_buf */ 0 : \
+           (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \
+           (m)->m_data - (m)->m_dat)
+
+/*
+ * Compute the amount of space available
+ * after the end of data in an mbuf.
+ */
+#define        M_TRAILINGSPACE(m) \
+       ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size - \
+           ((m)->m_data + (m)->m_len) : \
+           &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len))
+
+/*
+ * Arrange to prepend space of size plen to mbuf m.
+ * If a new mbuf must be allocated, how specifies whether to wait.
+ * If how is M_DONTWAIT and allocation fails, the original mbuf chain
+ * is freed and m is set to NULL.
+ */
+#define        M_PREPEND(m, plen, how) { \
+       if (M_LEADINGSPACE(m) >= (plen)) { \
+               (m)->m_data -= (plen); \
+               (m)->m_len += (plen); \
+       } else \
+               (m) = m_prepend((m), (plen), (how)); \
+       if ((m) && (m)->m_flags & M_PKTHDR) \
+               (m)->m_pkthdr.len += (plen); \
+}
+
+/* change mbuf to new type */
+#define MCHTYPE(m, t) { \
+       mbstat.m_mtypes[(m)->m_type]--; \
+       mbstat.m_mtypes[t]++; \
+       (m)->m_type = t;\
+}
+
+/* length to m_copy to copy all */
+#define        M_COPYALL       1000000000
+
+/* compatiblity with 4.3 */
+#define  m_copy(m, o, l)       m_copym((m), (o), (l), M_DONTWAIT)
+
+/*
+ * Mbuf statistics.
+ */
+struct mbstat {
+       u_long  m_mbufs;        /* mbufs obtained from page pool */
+       u_long  m_clusters;     /* clusters obtained from page pool */
+       u_long  m_spare;        /* spare field */
+       u_long  m_clfree;       /* free clusters */
+       u_long  m_drops;        /* times failed to find space */
+       u_long  m_wait;         /* times waited for space */
+       u_long  m_drain;        /* times drained protocols for space */
+       u_short m_mtypes[256];  /* type specific mbuf allocations */
+};
+
+#ifdef KERNEL
+extern struct mbuf *mbutl;             /* virtual address of mclusters */
+extern char *mclrefcnt;                /* cluster reference counts */
+struct mbstat mbstat;
+int    nmbclusters;
+union  mcluster *mclfree;
+int    max_linkhdr;                    /* largest link-level header */
+int    max_protohdr;                   /* largest protocol header */
+int    max_hdr;                        /* largest link+protocol header */
+int    max_datalen;                    /* MHLEN - max_hdr */
+struct mbuf *m_get(), *m_gethdr(), *m_getclr(), *m_retry(), *m_retryhdr();
+struct mbuf *m_free(), *m_copym(), *m_pullup(), *m_prepend();
+int    m_clalloc();
+extern int mbtypes[];                  /* XXX */
+
+#ifdef MBTYPES
+int mbtypes[] = {                              /* XXX */
+       M_FREE,         /* MT_FREE      0       /* should be on free list */
+       M_MBUF,         /* MT_DATA      1       /* dynamic (data) allocation */
+       M_MBUF,         /* MT_HEADER    2       /* packet header */
+       M_SOCKET,       /* MT_SOCKET    3       /* socket structure */
+       M_PCB,          /* MT_PCB       4       /* protocol control block */
+       M_RTABLE,       /* MT_RTABLE    5       /* routing tables */
+       M_HTABLE,       /* MT_HTABLE    6       /* IMP host tables */
+       0,              /* MT_ATABLE    7       /* address resolution tables */
+       M_MBUF,         /* MT_SONAME    8       /* socket name */
+       0,              /*              9 */
+       M_SOOPTS,       /* MT_SOOPTS    10      /* socket options */
+       M_FTABLE,       /* MT_FTABLE    11      /* fragment reassembly header */
+       M_MBUF,         /* MT_RIGHTS    12      /* access rights */
+       M_IFADDR,       /* MT_IFADDR    13      /* interface address */
+       M_MBUF,         /* MT_CONTROL   14      /* extra-data protocol message */
+       M_MBUF,         /* MT_OOBDATA   15      /* expedited data  */
+#ifdef DATAKIT
+       25, 26, 27, 28, 29, 30, 31, 32          /* datakit ugliness */
+#endif
+};
+#endif
+#endif
diff --git a/usr/src/sys.386bsd/sys/mman.h b/usr/src/sys.386bsd/sys/mman.h
new file mode 100644 (file)
index 0000000..b3e19d7
--- /dev/null
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mman.h      7.5 (Berkeley) 6/27/91
+ */
+
+/*
+ * Protections are chosen from these bits, or-ed together
+ */
+#define        PROT_READ       0x04    /* pages can be read */
+#define        PROT_WRITE      0x02    /* pages can be written */
+#define        PROT_EXEC       0x01    /* pages can be executed */
+
+/*
+ * Flags contain mapping type, sharing type and options.
+ * Mapping type; choose one
+ */
+#define        MAP_FILE        0x0001  /* mapped from a file or device */
+#define        MAP_ANON        0x0002  /* allocated from memory, swap space */
+#define        MAP_TYPE        0x000f  /* mask for type field */
+
+/*
+ * Sharing types; choose one
+ */
+#define        MAP_COPY        0x0020  /* "copy" region at mmap time */
+#define        MAP_SHARED      0x0010  /* share changes */
+#define        MAP_PRIVATE     0x0000  /* changes are private */
+
+/*
+ * Other flags
+ */
+#define        MAP_FIXED       0x0100  /* map addr must be exactly as requested */
+#define        MAP_NOEXTEND    0x0200  /* for MAP_FILE, don't change file size */
+#define        MAP_HASSEMPHORE 0x0400  /* region may contain semaphores */
+#define        MAP_INHERIT     0x0800  /* region is retained after exec */
+
+/*
+ * Advice to madvise
+ */
+#define        MADV_NORMAL     0       /* no further special treatment */
+#define        MADV_RANDOM     1       /* expect random page references */
+#define        MADV_SEQUENTIAL 2       /* expect sequential page references */
+#define        MADV_WILLNEED   3       /* will need these pages */
+#define        MADV_DONTNEED   4       /* dont need these pages */
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+/* Some of these int's should probably be size_t's */
+caddr_t        mmap __P((caddr_t, size_t, int, int, int, off_t));
+int    mprotect __P((caddr_t, int, int));
+int    munmap __P((caddr_t, int));
+int    msync __P((caddr_t, int));
+__END_DECLS
+
+#endif /* !KERNEL */
diff --git a/usr/src/sys.386bsd/sys/msgbuf.h b/usr/src/sys.386bsd/sys/msgbuf.h
new file mode 100644 (file)
index 0000000..821b124
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1981, 1984 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)msgbuf.h    7.5 (Berkeley) 5/2/91
+ */
+
+#define        MSG_BSIZE       (4096 - 3 * sizeof(long))
+struct msgbuf {
+#define        MSG_MAGIC       0x063061
+       long    msg_magic;
+       long    msg_bufx;               /* write pointer */
+       long    msg_bufr;               /* read pointer */
+       char    msg_bufc[MSG_BSIZE];    /* buffer */
+};
+#ifdef KERNEL
+struct msgbuf *msgbufp;
+#endif
diff --git a/usr/src/sys.386bsd/sys/mtio.h b/usr/src/sys.386bsd/sys/mtio.h
new file mode 100644 (file)
index 0000000..e42c92b
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mtio.h      7.6 (Berkeley) 2/5/91
+ */
+
+/*
+ * Structures and definitions for mag tape io control commands
+ */
+
+/* structure for MTIOCTOP - mag tape op command */
+struct mtop {
+       short   mt_op;          /* operations defined below */
+       daddr_t mt_count;       /* how many of them */
+};
+
+/* operations */
+#define MTWEOF         0       /* write an end-of-file record */
+#define MTFSF          1       /* forward space file */
+#define MTBSF          2       /* backward space file */
+#define MTFSR          3       /* forward space record */
+#define MTBSR          4       /* backward space record */
+#define MTREW          5       /* rewind */
+#define MTOFFL         6       /* rewind and put the drive offline */
+#define MTNOP          7       /* no operation, sets status only */
+#define MTCACHE                8       /* enable controller cache */
+#define MTNOCACHE      9       /* disable controller cache */
+
+/* structure for MTIOCGET - mag tape get status command */
+
+struct mtget {
+       short   mt_type;        /* type of magtape device */
+/* the following two registers are grossly device dependent */
+       short   mt_dsreg;       /* ``drive status'' register */
+       short   mt_erreg;       /* ``error'' register */
+/* end device-dependent registers */
+       short   mt_resid;       /* residual count */
+/* the following two are not yet implemented */
+       daddr_t mt_fileno;      /* file number of current position */
+       daddr_t mt_blkno;       /* block number of current position */
+/* end not yet implemented */
+};
+
+/*
+ * Constants for mt_type byte.  These are the same
+ * for controllers compatible with the types listed.
+ */
+#define        MT_ISTS         0x01            /* TS-11 */
+#define        MT_ISHT         0x02            /* TM03 Massbus: TE16, TU45, TU77 */
+#define        MT_ISTM         0x03            /* TM11/TE10 Unibus */
+#define        MT_ISMT         0x04            /* TM78/TU78 Massbus */
+#define        MT_ISUT         0x05            /* SI TU-45 emulation on Unibus */
+#define        MT_ISCPC        0x06            /* SUN */
+#define        MT_ISAR         0x07            /* SUN */
+#define        MT_ISTMSCP      0x08            /* DEC TMSCP protocol (TU81, TK50) */
+#define MT_ISCY                0x09            /* CCI Cipher */
+#define MT_ISCT                0x0a            /* HP 1/4 tape */
+#define MT_ISFHP       0x0b            /* HP 7980 1/2 tape */
+#define MT_ISEXABYTE   0x0c            /* Exabyte */
+#define MT_ISEXA8200   0x0c            /* Exabyte EXB-8200 */
+#define MT_ISEXA8500   0x0d            /* Exabyte EXB-8500 */
+#define MT_ISVIPER1    0x0e            /* Archive Viper-150 */
+#define MT_ISPYTHON    0x0f            /* Archive Python (DAT) */
+#define MT_ISHPDAT     0x10            /* HP 35450A DAT drive */
+
+/* mag tape io control commands */
+#define        MTIOCTOP        _IOW('m', 1, struct mtop)       /* do a mag tape op */
+#define        MTIOCGET        _IOR('m', 2, struct mtget)      /* get tape status */
+#define MTIOCIEOT      _IO('m', 3)                     /* ignore EOT error */
+#define MTIOCEEOT      _IO('m', 4)                     /* enable EOT error */
+
+#ifndef KERNEL
+#define        DEFTAPE "/dev/rmt12"
+#endif
+
+#ifdef KERNEL
+/*
+ * minor device number
+ */
+
+#define        T_UNIT          003             /* unit selection */
+#define        T_NOREWIND      004             /* no rewind on close */
+#define        T_DENSEL        030             /* density select */
+#define        T_800BPI        000             /* select  800 bpi */
+#define        T_1600BPI       010             /* select 1600 bpi */
+#define        T_6250BPI       020             /* select 6250 bpi */
+#define        T_BADBPI        030             /* undefined selection */
+#endif
diff --git a/usr/src/sys.386bsd/sys/namei.h b/usr/src/sys.386bsd/sys/namei.h
new file mode 100644 (file)
index 0000000..9c8d5ac
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1985, 1989, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)namei.h     7.15 (Berkeley) 5/15/91
+ */
+
+#ifndef _NAMEI_H_
+#define        _NAMEI_H_
+
+/*
+ * Encapsulation of namei parameters.
+ */
+struct nameidata {
+       /*
+        * Arguments to namei.
+        */
+       caddr_t ni_dirp;                /* pathname pointer */
+       enum    uio_seg ni_segflg;      /* location of pathname */
+       u_long  ni_nameiop;             /* see below */
+       /*
+        * Arguments to lookup.
+        */
+       struct  ucred *ni_cred;         /* credentials */
+       struct  vnode *ni_startdir;     /* starting directory */
+       struct  vnode *ni_rootdir;      /* logical root directory */
+       /*
+        * Results
+        */
+       struct  vnode *ni_vp;           /* vnode of result */
+       struct  vnode *ni_dvp;          /* vnode of intermediate directory */
+       /*
+        * Shared between namei, lookup routines, and commit routines.
+        */
+       char    *ni_pnbuf;              /* pathname buffer */
+       long    ni_pathlen;             /* remaining chars in path */
+       char    *ni_ptr;                /* current location in pathname */
+       long    ni_namelen;             /* length of current component */
+       char    *ni_next;               /* next location in pathname */
+       u_long  ni_hash;                /* hash value of current component */
+       u_char  ni_loopcnt;             /* count of symlinks encountered */
+       u_char  ni_makeentry;           /* 1 => add entry to name cache */
+       u_char  ni_isdotdot;            /* 1 => current component name is .. */
+       u_char  ni_more;                /* 1 => symlink needs interpretation */
+       /*
+        * Side effects.
+        */
+       struct ufs_specific {           /* saved info for new dir entry */
+               off_t   ufs_endoff;     /* end of useful directory contents */
+               long    ufs_offset;     /* offset of free space in directory */
+               long    ufs_count;      /* size of free slot in directory */
+               ino_t   ufs_ino;        /* inode number of found directory */
+               u_long  ufs_reclen;     /* size of found directory entry */
+       } ni_ufs;
+};
+
+#ifdef KERNEL
+/*
+ * namei operations
+ */
+#define        LOOKUP          0       /* perform name lookup only */
+#define        CREATE          1       /* setup for file creation */
+#define        DELETE          2       /* setup for file deletion */
+#define        RENAME          3       /* setup for file renaming */
+#define        OPMASK          3       /* mask for operation */
+/*
+ * namei operational modifiers
+ */
+#define        LOCKLEAF        0x0004  /* lock inode on return */
+#define        LOCKPARENT      0x0008  /* want parent vnode returned locked */
+#define        WANTPARENT      0x0010  /* want parent vnode returned unlocked */
+#define        NOCACHE         0x0020  /* name must not be left in cache */
+#define        FOLLOW          0x0040  /* follow symbolic links */
+#define        NOFOLLOW        0x0000  /* do not follow symbolic links (pseudo) */
+#define        MODMASK         0x00fc  /* mask of operational modifiers */
+/*
+ * Namei parameter descriptors.
+ *
+ * SAVENAME may be set by either the callers of namei or by VOP_LOOKUP.
+ * If the caller of namei sets the flag (for example execve wants to
+ * know the name of the program that is being executed), then it must
+ * free the buffer. If VOP_LOOKUP sets the flag, then the buffer must
+ * be freed by either the commit routine or the VOP_ABORT routine.
+ * SAVESTART is set only by the callers of namei. It implies SAVENAME
+ * plus the addition of saving the parent directory that contains the
+ * name in ni_startdir. It allows repeated calls to lookup for the
+ * name being sought. The caller is responsible for releasing the
+ * buffer and for vrele'ing ni_startdir.
+ */
+#define        NOCROSSMOUNT    0x0100  /* do not cross mount points */
+#define        REMOTE          0x0200  /* lookup for remote filesystem servers */
+#define        HASBUF          0x0400  /* has allocated pathname buffer */
+#define        SAVENAME        0x0800  /* save pathanme buffer */
+#define        SAVESTART       0x1000  /* save starting directory */
+#define PARAMASK       0xff00  /* mask of parameter descriptors */
+#endif
+
+/*
+ * This structure describes the elements in the cache of recent
+ * names looked up by namei. NCHNAMLEN is sized to make structure
+ * size a power of two to optimize malloc's. Minimum reasonable
+ * size is 15.
+ */
+
+#define        NCHNAMLEN       31      /* maximum name segment length we bother with */
+
+struct namecache {
+       struct  namecache *nc_forw;     /* hash chain, MUST BE FIRST */
+       struct  namecache *nc_back;     /* hash chain, MUST BE FIRST */
+       struct  namecache *nc_nxt;      /* LRU chain */
+       struct  namecache **nc_prev;    /* LRU chain */
+       struct  vnode *nc_dvp;          /* vnode of parent of name */
+       u_long  nc_dvpid;               /* capability number of nc_dvp */
+       struct  vnode *nc_vp;           /* vnode the name refers to */
+       u_long  nc_vpid;                /* capability number of nc_vp */
+       char    nc_nlen;                /* length of name */
+       char    nc_name[NCHNAMLEN];     /* segment name */
+};
+
+#ifdef KERNEL
+u_long nextvnodeid;
+int    namei __P((struct nameidata *ndp, struct proc *p));
+int    lookup __P((struct nameidata *ndp, struct proc *p));
+#endif
+
+/*
+ * Stats on usefulness of namei caches.
+ */
+struct nchstats {
+       long    ncs_goodhits;           /* hits that we can really use */
+       long    ncs_neghits;            /* negative hits that we can use */
+       long    ncs_badhits;            /* hits we must drop */
+       long    ncs_falsehits;          /* hits with id mismatch */
+       long    ncs_miss;               /* misses */
+       long    ncs_long;               /* long names that ignore cache */
+       long    ncs_pass2;              /* names found with passes == 2 */
+       long    ncs_2passes;            /* number of times we attempt it */
+};
+#endif /* !_NAMEI_H_ */
diff --git a/usr/src/sys.386bsd/sys/proc.h b/usr/src/sys.386bsd/sys/proc.h
new file mode 100644 (file)
index 0000000..f41c2d0
--- /dev/null
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 1986, 1989, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)proc.h      7.28 (Berkeley) 5/30/91
+ */
+
+#ifndef _PROC_H_
+#define        _PROC_H_
+
+#include <machine/proc.h>              /* machine-dependent proc substruct */
+
+/*
+ * One structure allocated per session.
+ */
+struct session {
+       int     s_count;                /* ref cnt; pgrps in session */
+       struct  proc *s_leader;         /* session leader */
+       struct  vnode *s_ttyvp;         /* vnode of controlling terminal */
+       struct  tty *s_ttyp;            /* controlling terminal */
+       char    s_login[MAXLOGNAME];    /* setlogin() name */
+};
+
+/*
+ * One structure allocated per process group.
+ */
+struct pgrp {
+       struct  pgrp *pg_hforw;         /* forward link in hash bucket */
+       struct  proc *pg_mem;           /* pointer to pgrp members */
+       struct  session *pg_session;    /* pointer to session */
+       pid_t   pg_id;                  /* pgrp id */
+       int     pg_jobc;        /* # procs qualifying pgrp for job control */
+};
+
+/*
+ * Description of a process.
+ * This structure contains the information needed to manage a thread
+ * of control, known in UN*X as a process; it has references to substructures
+ * containing descriptions of things that the process uses, but may share
+ * with related processes.  The process structure and the substructures
+ * are always addressible except for those marked "(PROC ONLY)" below,
+ * which might be addressible only on a processor on which the process
+ * is running.
+ */
+struct proc {
+       struct  proc *p_link;           /* doubly-linked run/sleep queue */
+       struct  proc *p_rlink;
+       struct  proc *p_nxt;            /* linked list of active procs */
+       struct  proc **p_prev;          /*    and zombies */
+
+       /* substructures: */
+       struct  pcred *p_cred;          /* process owner's identity */
+       struct  filedesc *p_fd;         /* ptr to open files structure */
+       struct  pstats *p_stats;        /* accounting/statistics (PROC ONLY) */
+       struct  plimit *p_limit;        /* process limits */
+       struct  vmspace *p_vmspace;     /* address space */
+       struct  sigacts *p_sigacts;     /* signal actions, state (PROC ONLY) */
+
+#define        p_ucred         p_cred->pc_ucred
+#define        p_rlimit        p_limit->pl_rlimit
+
+       int     p_flag;
+       char    p_stat;
+/*     char    p_space; */
+
+       pid_t   p_pid;          /* unique process id */
+       struct  proc *p_hash;   /* hashed based on p_pid for kill+exit+... */
+       struct  proc *p_pgrpnxt; /* pointer to next process in process group */
+       struct  proc *p_pptr;   /* pointer to process structure of parent */
+       struct  proc *p_osptr;  /* pointer to older sibling processes */
+
+/* The following fields are all zeroed upon creation in fork */
+#define        p_startzero     p_ysptr
+       struct  proc *p_ysptr;  /* pointer to younger siblings */
+       struct  proc *p_cptr;   /* pointer to youngest living child */
+
+       /* scheduling */
+       u_int   p_cpu;          /* cpu usage for scheduling */
+       int     p_cpticks;      /* ticks of cpu time */
+       fixpt_t p_pctcpu;       /* %cpu for this process during p_time */
+       caddr_t p_wchan;        /* event process is awaiting */
+       u_int   p_time;         /* resident/nonresident time for swapping */
+       u_int   p_slptime;      /* time since last block */
+
+       struct  itimerval p_realtimer;  /* alarm timer */
+       struct  timeval p_utime;        /* user time */
+       struct  timeval p_stime;        /* system time */
+
+       int     p_traceflag;    /* kernel trace points */
+       struct  vnode *p_tracep;/* trace to vnode */
+
+       int     p_sig;          /* signals pending to this process */
+
+/* end area that is zeroed on creation */
+#define        p_endzero       p_startcopy
+
+/* The following fields are all copied upon creation in fork */
+       sigset_t p_sigmask;     /* current signal mask */
+#define        p_startcopy     p_sigmask
+       sigset_t p_sigignore;   /* signals being ignored */
+       sigset_t p_sigcatch;    /* signals being caught by user */
+
+       u_char  p_pri;          /* priority, negative is high */
+       u_char  p_usrpri;       /* user-priority based on p_cpu and p_nice */
+       char    p_nice;         /* nice for cpu usage */
+/*     char    p_space1; */
+
+       struct  pgrp *p_pgrp;   /* pointer to process group */
+       char    p_comm[MAXCOMLEN+1];
+
+/* end area that is copied on creation */
+#define        p_endcopy       p_wmesg
+       char    *p_wmesg;       /* reason for sleep */
+       int     p_thread;       /* id for this "thread" (Mach glue) XXX */
+       struct  user *p_addr;   /* kernel virtual addr of u-area (PROC ONLY) */
+       swblk_t p_swaddr;       /* disk address of u area when swapped */
+       int     *p_regs;        /* saved registers during syscall/trap */
+       struct  mdproc p_md;    /* any machine-dependent fields */
+
+       u_short p_xstat;        /* Exit status for wait; also stop signal */
+       u_short p_dupfd;        /* sideways return value from fdopen XXX */
+       u_short p_acflag;       /* accounting flags */
+/*     short   p_space2; */
+       struct  rusage *p_ru;   /* exit information XXX */
+
+       long    p_spare[4];     /* tmp spares to avoid shifting eproc */
+};
+
+#define        p_session       p_pgrp->pg_session
+#define        p_pgid          p_pgrp->pg_id
+
+/* MOVE TO ucred.h? */
+/*
+ * Shareable process credentials (always resident).
+ * This includes a reference to the current user credentials
+ * as well as real and saved ids that may be used to change ids.
+ */
+struct pcred {
+       struct  ucred *pc_ucred;        /* current credentials */
+       uid_t   p_ruid;                 /* real user id */
+       uid_t   p_svuid;                /* saved effective user id */
+       gid_t   p_rgid;                 /* real group id */
+       gid_t   p_svgid;                /* saved effective group id */
+       int     p_refcnt;               /* number of references */
+};
+
+/* stat codes */
+#define        SSLEEP  1               /* awaiting an event */
+#define        SWAIT   2               /* (abandoned state) */
+#define        SRUN    3               /* running */
+#define        SIDL    4               /* intermediate state in process creation */
+#define        SZOMB   5               /* intermediate state in process termination */
+#define        SSTOP   6               /* process being traced */
+
+/* flag codes */
+#define        SLOAD   0x0000001       /* in core */
+#define        SSYS    0x0000002       /* swapper or pager process */
+#define        SSINTR  0x0000004       /* sleep is interruptible */
+#define        SCTTY   0x0000008       /* has a controlling terminal */
+#define        SPPWAIT 0x0000010       /* parent is waiting for child to exec/exit */
+#define SEXEC  0x0000020       /* process called exec */
+#define        STIMO   0x0000040       /* timing out during sleep */
+#define        SSEL    0x0000080       /* selecting; wakeup/waiting danger */
+#define        SWEXIT  0x0000100       /* working on exiting */
+#define        SNOCLDSTOP 0x0000200    /* no SIGCHLD when children stop */
+/* the following three should probably be changed into a hold count */
+#define        SLOCK   0x0000400       /* process being swapped out */
+#define        SKEEP   0x0000800       /* another flag to prevent swap out */
+#define        SPHYSIO 0x0001000       /* doing physical i/o */
+#define        STRC    0x0004000       /* process is being traced */
+#define        SWTED   0x0008000       /* another tracing flag */
+#define        SADVLCK 0x0040000       /* process may hold a POSIX advisory lock */
+/* the following should be moved to machine-dependent areas */
+#define        SOWEUPC 0x0002000       /* owe process an addupc() call at next ast */
+#ifdef HPUXCOMPAT
+#define        SHPUX   0x0010000       /* HP-UX process (HPUXCOMPAT) */
+#else
+#define        SHPUX   0               /* not HP-UX process (HPUXCOMPAT) */
+#endif
+/* not currently in use (never set) */
+#define        SPAGE   0x0020000       /* process in page wait state */
+
+#ifdef KERNEL
+/*
+ * We use process IDs <= PID_MAX;
+ * PID_MAX + 1 must also fit in a pid_t
+ * (used to represent "no process group").
+ */
+#define        PID_MAX         30000
+#define        NO_PID          30001
+#define        PIDHASH(pid)    ((pid) & pidhashmask)
+
+#define SESS_LEADER(p) ((p)->p_session->s_leader == (p))
+#define        SESSHOLD(s)     ((s)->s_count++)
+#define        SESSRELE(s)     { \
+               if (--(s)->s_count == 0) \
+                       FREE(s, M_SESSION); \
+       }
+
+extern int pidhashmask;                /* in param.c */
+extern struct proc *pidhash[];         /* in param.c */
+struct proc *pfind();                  /* find process by id */
+extern struct pgrp *pgrphash[];        /* in param.c */
+struct         pgrp *pgfind();                 /* find process group by id */
+struct proc *zombproc, *allproc;       /* lists of procs in various states */
+extern struct proc proc0;              /* process slot for swapper */
+struct proc *initproc, *pageproc;      /* process slots for init, pager */
+extern struct proc *curproc;           /* current running proc */
+extern int nprocs, maxproc;            /* current and max number of procs */
+
+#define        NQS     32              /* 32 run queues */
+struct prochd {
+       struct  proc *ph_link;  /* linked list of running processes */
+       struct  proc *ph_rlink;
+} qs[NQS];
+
+int    whichqs;                /* bit mask summarizing non-empty qs's */
+#endif /* KERNEL */
+
+#endif /* !_PROC_H_ */
diff --git a/usr/src/sys.386bsd/sys/protosw.h b/usr/src/sys.386bsd/sys/protosw.h
new file mode 100644 (file)
index 0000000..6422287
--- /dev/null
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)protosw.h   7.8 (Berkeley) 4/28/91
+ */
+
+/*
+ * Protocol switch table.
+ *
+ * Each protocol has a handle initializing one of these structures,
+ * which is used for protocol-protocol and system-protocol communication.
+ *
+ * A protocol is called through the pr_init entry before any other.
+ * Thereafter it is called every 200ms through the pr_fasttimo entry and
+ * every 500ms through the pr_slowtimo for timer based actions.
+ * The system will call the pr_drain entry if it is low on space and
+ * this should throw away any non-critical data.
+ *
+ * Protocols pass data between themselves as chains of mbufs using
+ * the pr_input and pr_output hooks.  Pr_input passes data up (towards
+ * UNIX) and pr_output passes it down (towards the imps); control
+ * information passes up and down on pr_ctlinput and pr_ctloutput.
+ * The protocol is responsible for the space occupied by any the
+ * arguments to these entries and must dispose it.
+ *
+ * The userreq routine interfaces protocols to the system and is
+ * described below.
+ */
+struct protosw {
+       short   pr_type;                /* socket type used for */
+       struct  domain *pr_domain;      /* domain protocol a member of */
+       short   pr_protocol;            /* protocol number */
+       short   pr_flags;               /* see below */
+/* protocol-protocol hooks */
+       int     (*pr_input)();          /* input to protocol (from below) */
+       int     (*pr_output)();         /* output to protocol (from above) */
+       int     (*pr_ctlinput)();       /* control input (from below) */
+       int     (*pr_ctloutput)();      /* control output (from above) */
+/* user-protocol hook */
+       int     (*pr_usrreq)();         /* user request: see list below */
+/* utility hooks */
+       int     (*pr_init)();           /* initialization hook */
+       int     (*pr_fasttimo)();       /* fast timeout (200ms) */
+       int     (*pr_slowtimo)();       /* slow timeout (500ms) */
+       int     (*pr_drain)();          /* flush any excess space possible */
+};
+
+#define        PR_SLOWHZ       2               /* 2 slow timeouts per second */
+#define        PR_FASTHZ       5               /* 5 fast timeouts per second */
+
+/*
+ * Values for pr_flags.
+ * PR_ADDR requires PR_ATOMIC;
+ * PR_ADDR and PR_CONNREQUIRED are mutually exclusive.
+ */
+#define        PR_ATOMIC       0x01            /* exchange atomic messages only */
+#define        PR_ADDR         0x02            /* addresses given with messages */
+#define        PR_CONNREQUIRED 0x04            /* connection required by protocol */
+#define        PR_WANTRCVD     0x08            /* want PRU_RCVD calls */
+#define        PR_RIGHTS       0x10            /* passes capabilities */
+
+/*
+ * The arguments to usrreq are:
+ *     (*protosw[].pr_usrreq)(up, req, m, nam, opt);
+ * where up is a (struct socket *), req is one of these requests,
+ * m is a optional mbuf chain containing a message,
+ * nam is an optional mbuf chain containing an address,
+ * and opt is a pointer to a socketopt structure or nil.
+ * The protocol is responsible for disposal of the mbuf chain m,
+ * the caller is responsible for any space held by nam and opt.
+ * A non-zero return from usrreq gives an
+ * UNIX error number which should be passed to higher level software.
+ */
+#define        PRU_ATTACH              0       /* attach protocol to up */
+#define        PRU_DETACH              1       /* detach protocol from up */
+#define        PRU_BIND                2       /* bind socket to address */
+#define        PRU_LISTEN              3       /* listen for connection */
+#define        PRU_CONNECT             4       /* establish connection to peer */
+#define        PRU_ACCEPT              5       /* accept connection from peer */
+#define        PRU_DISCONNECT          6       /* disconnect from peer */
+#define        PRU_SHUTDOWN            7       /* won't send any more data */
+#define        PRU_RCVD                8       /* have taken data; more room now */
+#define        PRU_SEND                9       /* send this data */
+#define        PRU_ABORT               10      /* abort (fast DISCONNECT, DETATCH) */
+#define        PRU_CONTROL             11      /* control operations on protocol */
+#define        PRU_SENSE               12      /* return status into m */
+#define        PRU_RCVOOB              13      /* retrieve out of band data */
+#define        PRU_SENDOOB             14      /* send out of band data */
+#define        PRU_SOCKADDR            15      /* fetch socket's address */
+#define        PRU_PEERADDR            16      /* fetch peer's address */
+#define        PRU_CONNECT2            17      /* connect two sockets */
+/* begin for protocols internal use */
+#define        PRU_FASTTIMO            18      /* 200ms timeout */
+#define        PRU_SLOWTIMO            19      /* 500ms timeout */
+#define        PRU_PROTORCV            20      /* receive from below */
+#define        PRU_PROTOSEND           21      /* send to below */
+
+#define        PRU_NREQ                21
+
+#ifdef PRUREQUESTS
+char *prurequests[] = {
+       "ATTACH",       "DETACH",       "BIND",         "LISTEN",
+       "CONNECT",      "ACCEPT",       "DISCONNECT",   "SHUTDOWN",
+       "RCVD",         "SEND",         "ABORT",        "CONTROL",
+       "SENSE",        "RCVOOB",       "SENDOOB",      "SOCKADDR",
+       "PEERADDR",     "CONNECT2",     "FASTTIMO",     "SLOWTIMO",
+       "PROTORCV",     "PROTOSEND",
+};
+#endif
+
+/*
+ * The arguments to the ctlinput routine are
+ *     (*protosw[].pr_ctlinput)(cmd, sa, arg);
+ * where cmd is one of the commands below, sa is a pointer to a sockaddr,
+ * and arg is an optional caddr_t argument used within a protocol family.
+ */
+#define        PRC_IFDOWN              0       /* interface transition */
+#define        PRC_ROUTEDEAD           1       /* select new route if possible ??? */
+#define        PRC_QUENCH2             3       /* DEC congestion bit says slow down */
+#define        PRC_QUENCH              4       /* some one said to slow down */
+#define        PRC_MSGSIZE             5       /* message size forced drop */
+#define        PRC_HOSTDEAD            6       /* host appears to be down */
+#define        PRC_HOSTUNREACH         7       /* deprecated (use PRC_UNREACH_HOST) */
+#define        PRC_UNREACH_NET         8       /* no route to network */
+#define        PRC_UNREACH_HOST        9       /* no route to host */
+#define        PRC_UNREACH_PROTOCOL    10      /* dst says bad protocol */
+#define        PRC_UNREACH_PORT        11      /* bad port # */
+/* was PRC_UNREACH_NEEDFRAG    12         (use PRC_MSGSIZE) */
+#define        PRC_UNREACH_SRCFAIL     13      /* source route failed */
+#define        PRC_REDIRECT_NET        14      /* net routing redirect */
+#define        PRC_REDIRECT_HOST       15      /* host routing redirect */
+#define        PRC_REDIRECT_TOSNET     16      /* redirect for type of service & net */
+#define        PRC_REDIRECT_TOSHOST    17      /* redirect for tos & host */
+#define        PRC_TIMXCEED_INTRANS    18      /* packet lifetime expired in transit */
+#define        PRC_TIMXCEED_REASS      19      /* lifetime expired on reass q */
+#define        PRC_PARAMPROB           20      /* header incorrect */
+
+#define        PRC_NCMDS               21
+
+#define        PRC_IS_REDIRECT(cmd)    \
+       ((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST)
+
+#ifdef PRCREQUESTS
+char   *prcrequests[] = {
+       "IFDOWN", "ROUTEDEAD", "#2", "DEC-BIT-QUENCH2",
+       "QUENCH", "MSGSIZE", "HOSTDEAD", "#7",
+       "NET-UNREACH", "HOST-UNREACH", "PROTO-UNREACH", "PORT-UNREACH",
+       "#12", "SRCFAIL-UNREACH", "NET-REDIRECT", "HOST-REDIRECT",
+       "TOSNET-REDIRECT", "TOSHOST-REDIRECT", "TX-INTRANS", "TX-REASS",
+       "PARAMPROB"
+};
+#endif
+
+/*
+ * The arguments to ctloutput are:
+ *     (*protosw[].pr_ctloutput)(req, so, level, optname, optval);
+ * req is one of the actions listed below, so is a (struct socket *),
+ * level is an indication of which protocol layer the option is intended.
+ * optname is a protocol dependent socket option request,
+ * optval is a pointer to a mbuf-chain pointer, for value-return results.
+ * The protocol is responsible for disposal of the mbuf chain *optval
+ * if supplied,
+ * the caller is responsible for any space held by *optval, when returned.
+ * A non-zero return from usrreq gives an
+ * UNIX error number which should be passed to higher level software.
+ */
+#define        PRCO_GETOPT     0
+#define        PRCO_SETOPT     1
+
+#define        PRCO_NCMDS      2
+
+#ifdef PRCOREQUESTS
+char   *prcorequests[] = {
+       "GETOPT", "SETOPT",
+};
+#endif
+
+#ifdef KERNEL
+extern struct protosw *pffindproto(), *pffindtype();
+#endif
diff --git a/usr/src/sys.386bsd/sys/ptrace.h b/usr/src/sys.386bsd/sys/ptrace.h
new file mode 100644 (file)
index 0000000..e4ca21a
--- /dev/null
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1984 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ptrace.h    7.4 (Berkeley) 2/22/91
+ */
+
+#ifndef        _PTRACE_H_
+#define        _PTRACE_H_
+
+#define        PT_TRACE_ME     0       /* child declares it's being traced */
+#define        PT_READ_I       1       /* read word in child's I space */
+#define        PT_READ_D       2       /* read word in child's D space */
+#define        PT_READ_U       3       /* read word in child's user structure */
+#define        PT_WRITE_I      4       /* write word in child's I space */
+#define        PT_WRITE_D      5       /* write word in child's D space */
+#define        PT_WRITE_U      6       /* write word in child's user structure */
+#define        PT_CONTINUE     7       /* continue the child */
+#define        PT_KILL         8       /* kill the child process */
+#define        PT_STEP         9       /* single step the child */
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    ptrace __P((int _request, pid_t _pid, caddr_t _addr, int _data));
+__END_DECLS
+
+#endif /* !KERNEL */
+
+#endif /* !_PTRACE_H_ */
diff --git a/usr/src/sys.386bsd/sys/reboot.h b/usr/src/sys.386bsd/sys/reboot.h
new file mode 100644 (file)
index 0000000..3c33eea
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)reboot.h    7.6 (Berkeley) 6/28/90
+ */
+
+/*
+ * Arguments to reboot system call.
+ * These are passed to boot program in r11,
+ * and on to init.
+ */
+#define        RB_AUTOBOOT     0       /* flags for system auto-booting itself */
+
+#define        RB_ASKNAME      0x01    /* ask for file name to reboot from */
+#define        RB_SINGLE       0x02    /* reboot to single user only */
+#define        RB_NOSYNC       0x04    /* dont sync before reboot */
+#define        RB_HALT         0x08    /* don't reboot, just halt */
+#define        RB_INITNAME     0x10    /* name given for /etc/init (unused) */
+#define        RB_DFLTROOT     0x20    /* use compiled-in rootdev */
+#define        RB_KDB          0x40    /* give control to kernel debugger */
+#define        RB_RDONLY       0x80    /* mount root fs read-only */
+#define        RB_DUMP         0x100   /* dump kernel memory before reboot */
+
+/*
+ * Constants for converting boot-style device number to type,
+ * adaptor (uba, mba, etc), unit number and partition number.
+ * Type (== major device number) is in the low byte
+ * for backward compatibility.  Except for that of the "magic
+ * number", each mask applies to the shifted value.
+ * Format:
+ *      (4) (4) (4) (4)  (8)     (8)
+ *     --------------------------------
+ *     |MA | AD| CT| UN| PART  | TYPE |
+ *     --------------------------------
+ */
+#define        B_ADAPTORSHIFT          24
+#define        B_ADAPTORMASK           0x0f
+#define        B_ADAPTOR(val)          (((val) >> B_ADAPTORSHIFT) & B_ADAPTORMASK)
+#define B_CONTROLLERSHIFT      20
+#define B_CONTROLLERMASK       0xf
+#define        B_CONTROLLER(val)       (((val)>>B_CONTROLLERSHIFT) & B_CONTROLLERMASK)
+#define B_UNITSHIFT            16
+#define B_UNITMASK             0xf
+#define        B_UNIT(val)             (((val) >> B_UNITSHIFT) & B_UNITMASK)
+#define B_PARTITIONSHIFT       8
+#define B_PARTITIONMASK                0xff
+#define        B_PARTITION(val)        (((val) >> B_PARTITIONSHIFT) & B_PARTITIONMASK)
+#define        B_TYPESHIFT             0
+#define        B_TYPEMASK              0xff
+#define        B_TYPE(val)             (((val) >> B_TYPESHIFT) & B_TYPEMASK)
+
+#define        B_MAGICMASK     ((u_long)0xf0000000)
+#define        B_DEVMAGIC      ((u_long)0xa0000000)
+
+#define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \
+       (((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \
+       ((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \
+       ((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC)
diff --git a/usr/src/sys.386bsd/sys/resource.h b/usr/src/sys.386bsd/sys/resource.h
new file mode 100644 (file)
index 0000000..d440d3f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)resource.h  7.5 (Berkeley) 3/17/91
+ */
+
+#ifndef _RESOURCE_H_
+#define        _RESOURCE_H_
+
+/*
+ * Process priority specifications to get/setpriority.
+ */
+#define        PRIO_MIN        -20
+#define        PRIO_MAX        20
+
+#define        PRIO_PROCESS    0
+#define        PRIO_PGRP       1
+#define        PRIO_USER       2
+
+/*
+ * Resource utilization information.
+ */
+
+#define        RUSAGE_SELF     0
+#define        RUSAGE_CHILDREN -1
+
+struct rusage {
+       struct timeval ru_utime;        /* user time used */
+       struct timeval ru_stime;        /* system time used */
+       long    ru_maxrss;              /* max resident set size */
+#define        ru_first        ru_ixrss
+       long    ru_ixrss;               /* integral shared memory size */
+       long    ru_idrss;               /* integral unshared data " */
+       long    ru_isrss;               /* integral unshared stack " */
+       long    ru_minflt;              /* page reclaims */
+       long    ru_majflt;              /* page faults */
+       long    ru_nswap;               /* swaps */
+       long    ru_inblock;             /* block input operations */
+       long    ru_oublock;             /* block output operations */
+       long    ru_msgsnd;              /* messages sent */
+       long    ru_msgrcv;              /* messages received */
+       long    ru_nsignals;            /* signals received */
+       long    ru_nvcsw;               /* voluntary context switches */
+       long    ru_nivcsw;              /* involuntary " */
+#define        ru_last         ru_nivcsw
+};
+
+/*
+ * Resource limits
+ */
+#define        RLIMIT_CPU      0               /* cpu time in milliseconds */
+#define        RLIMIT_FSIZE    1               /* maximum file size */
+#define        RLIMIT_DATA     2               /* data size */
+#define        RLIMIT_STACK    3               /* stack size */
+#define        RLIMIT_CORE     4               /* core file size */
+#define        RLIMIT_RSS      5               /* resident set size */
+#define        RLIMIT_MEMLOCK  6               /* locked-in-memory address space */
+#define        RLIMIT_NPROC    7               /* number of processes */
+#define        RLIMIT_OFILE    8               /* number of open files */
+
+#define        RLIM_NLIMITS    9               /* number of resource limits */
+
+#define        RLIM_INFINITY   0x7fffffff
+
+struct rlimit {
+       long    rlim_cur;               /* current (soft) limit */
+       long    rlim_max;               /* maximum value for rlim_cur */
+};
+
+#ifndef KERNEL
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    getpriority __P((int, int));
+int    getrlimit __P((int, struct rlimit *));
+int    getrusage __P((int, struct rusage *));
+int    setpriority __P((int, int, int));
+int    setrlimit __P((int, const struct rlimit *));
+__END_DECLS
+
+#endif /* !KERNEL */
+#endif /* !_RESOURCE_H_ */
diff --git a/usr/src/sys.386bsd/sys/shm.h b/usr/src/sys.386bsd/sys/shm.h
new file mode 100644 (file)
index 0000000..4374d2d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)shm.h       7.2 (Berkeley) 2/5/91
+ */
+
+/*
+ * SVID compatible shm.h file
+ */
+#ifndef _SHM_H_
+#define _SHM_H_
+
+#ifdef KERNEL
+#include "ipc.h"
+#else
+#include <sys/ipc.h>
+#endif
+
+struct shmid_ds {
+       struct  ipc_perm shm_perm;      /* operation perms */
+       int     shm_segsz;              /* size of segment (bytes) */
+       ushort  shm_cpid;               /* pid, creator */
+       ushort  shm_lpid;               /* pid, last operation */
+       short   shm_nattch;             /* no. of current attaches */
+       time_t  shm_atime;              /* last attach time */
+       time_t  shm_dtime;              /* last detach time */
+       time_t  shm_ctime;              /* last change time */
+       void    *shm_handle;            /* internal handle for shm segment */
+};
+
+/*
+ * System 5 style catch-all structure for shared memory constants that
+ * might be of interest to user programs.  Do we really want/need this?
+ */
+struct shminfo {
+       int     shmmax;         /* max shared memory segment size (bytes) */
+       int     shmmin;         /* min shared memory segment size (bytes) */
+       int     shmmni;         /* max number of shared memory identifiers */
+       int     shmseg;         /* max shared memory segments per process */
+       int     shmall;         /* max amount of shared memory (pages) */
+};
+
+/* internal "mode" bits */
+#define        SHM_ALLOC       01000   /* segment is allocated */
+#define        SHM_DEST        02000   /* segment will be destroyed on last detach */
+
+/* SVID required constants (same values as system 5) */
+#define        SHM_RDONLY      010000  /* read-only access */
+#define        SHM_RND         020000  /* round attach address to SHMLBA boundary */
+
+/* implementation constants */
+#define        SHMLBA          CLBYTES /* segment low boundary address multiple */
+#define        SHMMMNI         512     /* maximum value for shminfo.shmmni */
+
+#ifdef KERNEL
+struct shmid_ds        *shmsegs;
+struct shminfo         shminfo;
+#endif
+
+#endif /* !_SHM_H_ */
diff --git a/usr/src/sys.386bsd/sys/signalvar.h b/usr/src/sys.386bsd/sys/signalvar.h
new file mode 100644 (file)
index 0000000..d446d93
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)signalvar.h 7.1 (Berkeley) 5/9/91
+ */
+
+#ifndef        _SIGNALVAR_H_           /* tmp for user.h */
+#define        _SIGNALVAR_H_
+
+/*
+ * Kernel signal definitions and data structures,
+ * not exported to user programs.
+ */
+
+/*
+ * Process signal actions and state, needed only within the process
+ * (not necessarily resident).
+ */
+struct sigacts {
+       sig_t   ps_sigact[NSIG];        /* disposition of signals */
+       sigset_t ps_catchmask[NSIG];    /* signals to be blocked */
+       sigset_t ps_sigonstack;         /* signals to take on sigstack */
+       sigset_t ps_sigintr;            /* signals that interrupt syscalls */
+       sigset_t ps_oldmask;            /* saved mask from before sigpause */
+       int     ps_flags;               /* signal flags, below */
+       struct  sigstack ps_sigstack;   /* sp & on stack state variable */
+       int     ps_sig;                 /* for core dump/debugger XXX */
+       int     ps_code;                /* for core dump/debugger XXX */
+};
+
+#define        ps_onstack      ps_sigstack.ss_onstack
+#define        ps_sigsp        ps_sigstack.ss_sp
+
+/* signal flags */
+#define        SA_OLDMASK      0x01            /* need to restore mask before pause */
+
+/* additional signal action values, used only temporarily/internally */
+#define        SIG_CATCH       (void (*)())2
+#define        SIG_HOLD        (void (*)())3
+
+/*
+ * get signal action for process and signal; currently only for current process
+ */
+#define SIGACTION(p, sig)      (p->p_sigacts->ps_sigact[(sig)])
+
+/*
+ * Determine signal that should be delivered to process p, the current process,
+ * 0 if none.  If there is a pending stop signal with default action,
+ * the process stops in issig().
+ */
+#define        CURSIG(p) \
+       (((p)->p_sig == 0 || \
+           ((p)->p_flag&STRC) == 0 && ((p)->p_sig &~ (p)->p_sigmask) == 0) ? \
+           0 : issig(p))
+
+/*
+ * Clear a pending signal from a process.
+ */
+#define        CLRSIG(p, sig)  { (p)->p_sig &= ~sigmask(sig); }
+
+/*
+ * Signal properties and actions.
+ * The array below categorizes the signals and their default actions
+ * according to the following properties:
+ */
+#define        SA_KILL         0x01            /* terminates process by default */
+#define        SA_CORE         0x02            /* ditto and coredumps */
+#define        SA_STOP         0x04            /* suspend process */
+#define        SA_TTYSTOP      (0x08|SA_STOP)  /* ditto, from tty */
+#define        SA_IGNORE       0x10            /* ignore by default */
+#define        SA_CONT         0x20            /* continue if suspended */
+#define        SA_CANTMASK     0x40            /* non-maskable, catchable */
+
+#ifdef SIGPROP
+int sigprop[NSIG + 1] = {
+       0,                      /* unused */
+       SA_KILL,                /* SIGHUP */
+       SA_KILL,                /* SIGINT */
+       SA_KILL|SA_CORE,        /* SIGQUIT */
+       SA_KILL|SA_CORE,        /* SIGILL */
+       SA_KILL|SA_CORE,        /* SIGTRAP */
+       SA_KILL|SA_CORE,        /* SIGABRT */
+       SA_KILL|SA_CORE,        /* SIGEMT */
+       SA_KILL|SA_CORE,        /* SIGFPE */
+       SA_KILL,                /* SIGKILL */
+       SA_KILL|SA_CORE,        /* SIGBUS */
+       SA_KILL|SA_CORE,        /* SIGSEGV */
+       SA_KILL|SA_CORE,        /* SIGSYS */
+       SA_KILL,                /* SIGPIPE */
+       SA_KILL,                /* SIGALRM */
+       SA_KILL,                /* SIGTERM */
+       SA_IGNORE,              /* SIGURG */
+       SA_STOP,                /* SIGSTOP */
+       SA_TTYSTOP,             /* SIGTSTP */
+       SA_IGNORE|SA_CONT,      /* SIGCONT */
+       SA_IGNORE,              /* SIGCHLD */
+       SA_TTYSTOP,             /* SIGTTIN */
+       SA_TTYSTOP,             /* SIGTTOU */
+       SA_IGNORE,              /* SIGIO */
+       SA_KILL,                /* SIGXCPU */
+       SA_KILL,                /* SIGXFSZ */
+       SA_KILL,                /* SIGVTALRM */
+       SA_KILL,                /* SIGPROF */
+       SA_IGNORE,              /* SIGWINCH  */
+       SA_IGNORE,              /* SIGINFO */
+       SA_KILL,                /* SIGUSR1 */
+       SA_KILL,                /* SIGUSR2 */
+};
+
+#define        stopsigmask     (sigmask(SIGSTOP)|sigmask(SIGTSTP)|\
+                        sigmask(SIGTTIN)|sigmask(SIGTTOU))
+#define        contsigmask     (sigmask(SIGCONT))
+
+#endif /* SIGPROP */
+
+#define        sigcantmask     (sigmask(SIGKILL)|sigmask(SIGSTOP))
+
+#ifdef KERNEL
+/*
+ * Machine-independent functions:
+ */
+void   siginit __P((struct proc *p));
+void   execsigs __P((struct proc *p));
+void   gsignal __P((int pgid, int sig));
+void   pgsignal __P((struct pgrp *pgrp, int sig, int checkctty));
+void   trapsignal __P((struct proc *p, int sig, unsigned code));
+void   psignal __P((struct proc *p, int sig));
+int    issig __P((struct proc *p));
+void   psig __P((int sig));
+int    coredump __P((struct proc *p));
+
+/*
+ * Machine-dependent functions:
+ */
+void   sendsig __P((sig_t action, int sig, int returnmask, unsigned code));
+#endif /* KERNEL */
+#endif /* !_SIGNALVAR_H_ */
diff --git a/usr/src/sys.386bsd/sys/socket.h b/usr/src/sys.386bsd/sys/socket.h
new file mode 100644 (file)
index 0000000..58febae
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 1982,1985,1986,1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)socket.h    7.13 (Berkeley) 4/20/91
+ */
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+/*
+ * Types
+ */
+#define        SOCK_STREAM     1               /* stream socket */
+#define        SOCK_DGRAM      2               /* datagram socket */
+#define        SOCK_RAW        3               /* raw-protocol interface */
+#define        SOCK_RDM        4               /* reliably-delivered message */
+#define        SOCK_SEQPACKET  5               /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define        SO_DEBUG        0x0001          /* turn on debugging info recording */
+#define        SO_ACCEPTCONN   0x0002          /* socket has had listen() */
+#define        SO_REUSEADDR    0x0004          /* allow local address reuse */
+#define        SO_KEEPALIVE    0x0008          /* keep connections alive */
+#define        SO_DONTROUTE    0x0010          /* just use interface addresses */
+#define        SO_BROADCAST    0x0020          /* permit sending of broadcast msgs */
+#define        SO_USELOOPBACK  0x0040          /* bypass hardware when possible */
+#define        SO_LINGER       0x0080          /* linger on close if data present */
+#define        SO_OOBINLINE    0x0100          /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF      0x1001          /* send buffer size */
+#define SO_RCVBUF      0x1002          /* receive buffer size */
+#define SO_SNDLOWAT    0x1003          /* send low-water mark */
+#define SO_RCVLOWAT    0x1004          /* receive low-water mark */
+#define SO_SNDTIMEO    0x1005          /* send timeout */
+#define SO_RCVTIMEO    0x1006          /* receive timeout */
+#define        SO_ERROR        0x1007          /* get error status and clear */
+#define        SO_TYPE         0x1008          /* get socket type */
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+       int     l_onoff;                /* option on/off */
+       int     l_linger;               /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define        SOL_SOCKET      0xffff          /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define        AF_UNSPEC       0               /* unspecified */
+#define        AF_UNIX         1               /* local to host (pipes, portals) */
+#define        AF_INET         2               /* internetwork: UDP, TCP, etc. */
+#define        AF_IMPLINK      3               /* arpanet imp addresses */
+#define        AF_PUP          4               /* pup protocols: e.g. BSP */
+#define        AF_CHAOS        5               /* mit CHAOS protocols */
+#define        AF_NS           6               /* XEROX NS protocols */
+#define        AF_ISO          7               /* ISO protocols */
+#define        AF_OSI          AF_ISO
+#define        AF_ECMA         8               /* european computer manufacturers */
+#define        AF_DATAKIT      9               /* datakit protocols */
+#define        AF_CCITT        10              /* CCITT protocols, X.25 etc */
+#define        AF_SNA          11              /* IBM SNA */
+#define AF_DECnet      12              /* DECnet */
+#define AF_DLI         13              /* DEC Direct data link interface */
+#define AF_LAT         14              /* LAT */
+#define        AF_HYLINK       15              /* NSC Hyperchannel */
+#define        AF_APPLETALK    16              /* Apple Talk */
+#define        AF_ROUTE        17              /* Internal Routing Protocol */
+#define        AF_LINK         18              /* Link layer interface */
+#define        pseudo_AF_XTP   19              /* eXpress Transfer Protocol (no AF) */
+
+#define        AF_MAX          20
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+       u_char  sa_len;                 /* total length */
+       u_char  sa_family;              /* address family */
+       char    sa_data[14];            /* actually longer; address value */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+       u_short sp_family;              /* address family */
+       u_short sp_protocol;            /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define        PF_UNSPEC       AF_UNSPEC
+#define        PF_UNIX         AF_UNIX
+#define        PF_INET         AF_INET
+#define        PF_IMPLINK      AF_IMPLINK
+#define        PF_PUP          AF_PUP
+#define        PF_CHAOS        AF_CHAOS
+#define        PF_NS           AF_NS
+#define        PF_ISO          AF_ISO
+#define        PF_OSI          AF_ISO
+#define        PF_ECMA         AF_ECMA
+#define        PF_DATAKIT      AF_DATAKIT
+#define        PF_CCITT        AF_CCITT
+#define        PF_SNA          AF_SNA
+#define PF_DECnet      AF_DECnet
+#define PF_DLI         AF_DLI
+#define PF_LAT         AF_LAT
+#define        PF_HYLINK       AF_HYLINK
+#define        PF_APPLETALK    AF_APPLETALK
+#define        PF_ROUTE        AF_ROUTE
+#define        PF_LINK         AF_LINK
+#define        PF_XTP          pseudo_AF_XTP   /* really just proto family, no AF */
+
+#define        PF_MAX          AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define        SOMAXCONN       5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recvmsg, value only for sendmsg.
+ */
+struct msghdr {
+       caddr_t msg_name;               /* optional address */
+       u_int   msg_namelen;            /* size of address */
+       struct  iovec *msg_iov;         /* scatter/gather array */
+       u_int   msg_iovlen;             /* # elements in msg_iov */
+       caddr_t msg_control;            /* ancillary data, see below */
+       u_int   msg_controllen;         /* ancillary data buffer len */
+       int     msg_flags;              /* flags on received message */
+};
+
+#define        MSG_OOB         0x1             /* process out-of-band data */
+#define        MSG_PEEK        0x2             /* peek at incoming message */
+#define        MSG_DONTROUTE   0x4             /* send without using routing tables */
+#define        MSG_EOR         0x8             /* data completes record */
+#define        MSG_TRUNC       0x10            /* data discarded before delivery */
+#define        MSG_CTRUNC      0x20            /* control data lost before delivery */
+#define        MSG_WAITALL     0x40            /* wait for full request or error */
+
+/*
+ * Header for ancillary data objects in msg_control buffer.
+ * Used for additional information with/about a datagram
+ * not expressible by flags.  The format is a sequence
+ * of message elements headed by cmsghdr structures.
+ */
+struct cmsghdr {
+       u_int   cmsg_len;               /* data byte count, including hdr */
+       int     cmsg_level;             /* originating protocol */
+       int     cmsg_type;              /* protocol-specific type */
+/* followed by u_char  cmsg_data[]; */
+};
+
+/* given pointer to struct adatahdr, return pointer to data */
+#define        CMSG_DATA(cmsg)         ((u_char *)((cmsg) + 1))
+
+/* given pointer to struct adatahdr, return pointer to next adatahdr */
+#define        CMSG_NXTHDR(mhdr, cmsg) \
+       (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \
+           (mhdr)->msg_control + (mhdr)->msg_controllen) ? \
+           (struct cmsghdr *)NULL : \
+           (struct cmsghdr *)((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len)))
+
+#define        CMSG_FIRSTHDR(mhdr)     ((struct cmsghdr *)(mhdr)->msg_control)
+
+/* "Socket"-level control message types: */
+#define        SCM_RIGHTS      0x01            /* access rights (array of int) */
+
+/*
+ * 4.3 compat sockaddr, move to compat file later
+ */
+struct osockaddr {
+       u_short sa_family;              /* address family */
+       char    sa_data[14];            /* up to 14 bytes of direct address */
+};
+
+/*
+ * 4.3-compat message header (move to compat file later).
+ */
+struct omsghdr {
+       caddr_t msg_name;               /* optional address */
+       int     msg_namelen;            /* size of address */
+       struct  iovec *msg_iov;         /* scatter/gather array */
+       int     msg_iovlen;             /* # elements in msg_iov */
+       caddr_t msg_accrights;          /* access rights sent/received */
+       int     msg_accrightslen;
+};
+
+#ifndef        KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    accept __P((int, struct sockaddr *, int *));
+int    bind __P((int, const struct sockaddr *, int));
+int    connect __P((int, const struct sockaddr *, int));
+int    getpeername __P((int, struct sockaddr *, int *));
+int    getsockname __P((int, struct sockaddr *, int *));
+int    getsockopt __P((int, int, int, void *, int *));
+int    listen __P((int, int));
+int    recv __P((int, void *, int, int));
+int    recvfrom __P((int, void *, int, int,
+               struct sockaddr *, int *));
+int    recvmsg __P((int, struct msghdr *, int));
+int    send __P((int, const void *, int, int));
+int    sendto __P((int, const void *, int, int, const struct sockaddr *, int));
+int    sendmsg __P((int, const struct msghdr *, int));
+int    setsockopt __P((int, int, int, const void *, int));
+int    shutdown __P((int, int));
+int    socket __P((int, int, int));
+int    socketpair __P((int, int, int, int *));
+__END_DECLS
+
+#endif /* !KERNEL */
diff --git a/usr/src/sys.386bsd/sys/socketvar.h b/usr/src/sys.386bsd/sys/socketvar.h
new file mode 100644 (file)
index 0000000..d8b6ac5
--- /dev/null
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)socketvar.h 7.17 (Berkeley) 5/5/91
+ */
+
+/*
+ * Kernel structure per socket.
+ * Contains send and receive buffer queues,
+ * handle on protocol and pointer to protocol
+ * private data and error information.
+ */
+struct socket {
+       short   so_type;                /* generic type, see socket.h */
+       short   so_options;             /* from socket call, see socket.h */
+       short   so_linger;              /* time to linger while closing */
+       short   so_state;               /* internal state flags SS_*, below */
+       caddr_t so_pcb;                 /* protocol control block */
+       struct  protosw *so_proto;      /* protocol handle */
+/*
+ * Variables for connection queueing.
+ * Socket where accepts occur is so_head in all subsidiary sockets.
+ * If so_head is 0, socket is not related to an accept.
+ * For head socket so_q0 queues partially completed connections,
+ * while so_q is a queue of connections ready to be accepted.
+ * If a connection is aborted and it has so_head set, then
+ * it has to be pulled out of either so_q0 or so_q.
+ * We allow connections to queue up based on current queue lengths
+ * and limit on number of queued connections for this socket.
+ */
+       struct  socket *so_head;        /* back pointer to accept socket */
+       struct  socket *so_q0;          /* queue of partial connections */
+       struct  socket *so_q;           /* queue of incoming connections */
+       short   so_q0len;               /* partials on so_q0 */
+       short   so_qlen;                /* number of connections on so_q */
+       short   so_qlimit;              /* max number queued connections */
+       short   so_timeo;               /* connection timeout */
+       u_short so_error;               /* error affecting connection */
+       pid_t   so_pgid;                /* pgid for signals */
+       u_long  so_oobmark;             /* chars to oob mark */
+/*
+ * Variables for socket buffering.
+ */
+       struct  sockbuf {
+               u_long  sb_cc;          /* actual chars in buffer */
+               u_long  sb_hiwat;       /* max actual char count */
+               u_long  sb_mbcnt;       /* chars of mbufs used */
+               u_long  sb_mbmax;       /* max chars of mbufs to use */
+               long    sb_lowat;       /* low water mark */
+               struct  mbuf *sb_mb;    /* the mbuf chain */
+               struct  proc *sb_sel;   /* process selecting read/write */
+               short   sb_flags;       /* flags, see below */
+               short   sb_timeo;       /* timeout for read/write */
+       } so_rcv, so_snd;
+#define        SB_MAX          (64*1024)       /* default for max chars in sockbuf */
+#define        SB_LOCK         0x01            /* lock on data queue */
+#define        SB_WANT         0x02            /* someone is waiting to lock */
+#define        SB_WAIT         0x04            /* someone is waiting for data/space */
+#define        SB_SEL          0x08            /* someone is selecting */
+#define        SB_ASYNC        0x10            /* ASYNC I/O, need signals */
+#define        SB_NOTIFY       (SB_WAIT|SB_SEL|SB_ASYNC)
+#define        SB_COLL         0x20            /* collision selecting */
+#define        SB_NOINTR       0x40            /* operations not interruptible */
+
+       caddr_t so_tpcb;                /* Wisc. protocol control block XXX */
+};
+
+/*
+ * Socket state bits.
+ */
+#define        SS_NOFDREF              0x001   /* no file table ref any more */
+#define        SS_ISCONNECTED          0x002   /* socket connected to a peer */
+#define        SS_ISCONNECTING         0x004   /* in process of connecting to peer */
+#define        SS_ISDISCONNECTING      0x008   /* in process of disconnecting */
+#define        SS_CANTSENDMORE         0x010   /* can't send more data to peer */
+#define        SS_CANTRCVMORE          0x020   /* can't receive more data from peer */
+#define        SS_RCVATMARK            0x040   /* at mark on input */
+
+#define        SS_PRIV                 0x080   /* privileged for broadcast, raw... */
+#define        SS_NBIO                 0x100   /* non-blocking ops */
+#define        SS_ASYNC                0x200   /* async i/o notify */
+#define        SS_ISCONFIRMING         0x400   /* deciding to accept connection req */
+
+
+/*
+ * Macros for sockets and socket buffering.
+ */
+
+/*
+ * How much space is there in a socket buffer (so->so_snd or so->so_rcv)?
+ * This is problematical if the fields are unsigned, as the space might
+ * still be negative (cc > hiwat or mbcnt > mbmax).  Should detect
+ * overflow and return 0.  Should use "lmin" but it doesn't exist now.
+ */
+#define        sbspace(sb) \
+    ((long) imin((int)((sb)->sb_hiwat - (sb)->sb_cc), \
+        (int)((sb)->sb_mbmax - (sb)->sb_mbcnt)))
+
+/* do we have to send all at once on a socket? */
+#define        sosendallatonce(so) \
+    ((so)->so_proto->pr_flags & PR_ATOMIC)
+
+/* can we read something from so? */
+#define        soreadable(so) \
+    ((so)->so_rcv.sb_cc >= (so)->so_rcv.sb_lowat || \
+       ((so)->so_state & SS_CANTRCVMORE) || \
+       (so)->so_qlen || (so)->so_error)
+
+/* can we write something to so? */
+#define        sowriteable(so) \
+    (sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat && \
+       (((so)->so_state&SS_ISCONNECTED) || \
+         ((so)->so_proto->pr_flags&PR_CONNREQUIRED)==0) || \
+     ((so)->so_state & SS_CANTSENDMORE) || \
+     (so)->so_error)
+
+/* adjust counters in sb reflecting allocation of m */
+#define        sballoc(sb, m) { \
+       (sb)->sb_cc += (m)->m_len; \
+       (sb)->sb_mbcnt += MSIZE; \
+       if ((m)->m_flags & M_EXT) \
+               (sb)->sb_mbcnt += (m)->m_ext.ext_size; \
+}
+
+/* adjust counters in sb reflecting freeing of m */
+#define        sbfree(sb, m) { \
+       (sb)->sb_cc -= (m)->m_len; \
+       (sb)->sb_mbcnt -= MSIZE; \
+       if ((m)->m_flags & M_EXT) \
+               (sb)->sb_mbcnt -= (m)->m_ext.ext_size; \
+}
+
+/*
+ * Set lock on sockbuf sb; sleep if lock is already held.
+ * Unless SB_NOINTR is set on sockbuf, sleep is interruptible.
+ * Returns error without lock if sleep is interrupted.
+ */
+#define sblock(sb) ((sb)->sb_flags & SB_LOCK ? sb_lock(sb) : \
+               ((sb)->sb_flags |= SB_LOCK, 0))
+
+/* release lock on sockbuf sb */
+#define        sbunlock(sb) { \
+       (sb)->sb_flags &= ~SB_LOCK; \
+       if ((sb)->sb_flags & SB_WANT) { \
+               (sb)->sb_flags &= ~SB_WANT; \
+               wakeup((caddr_t)&(sb)->sb_flags); \
+       } \
+}
+
+#define        sorwakeup(so)   sowakeup((so), &(so)->so_rcv)
+#define        sowwakeup(so)   sowakeup((so), &(so)->so_snd)
+
+#ifdef KERNEL
+u_long sb_max;
+/* to catch callers missing new second argument to sonewconn: */
+#define        sonewconn(head, connstatus)     sonewconn1((head), (connstatus))
+struct socket *sonewconn1 __P((struct socket *head, int connstatus));
+
+/* strings for sleep message: */
+extern char netio[], netcon[], netcls[];
+
+/*
+ * File operations on sockets.
+ */
+int    soo_read __P((struct file *fp, struct uio *uio, struct ucred *cred));
+int    soo_write __P((struct file *fp, struct uio *uio, struct ucred *cred));
+int    soo_ioctl __P((struct file *fp, int com, caddr_t data, struct proc *p));
+int    soo_select __P((struct file *fp, int which, struct proc *p));
+int    soo_close __P((struct file *fp, struct proc *p));
+#endif
diff --git a/usr/src/sys.386bsd/sys/specdev.h b/usr/src/sys.386bsd/sys/specdev.h
new file mode 100644 (file)
index 0000000..2012ca7
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)specdev.h   7.4 (Berkeley) 4/19/91
+ */
+
+/*
+ * This structure defines the information maintained about
+ * special devices. It is allocated in checkalias and freed
+ * in vgone.
+ */
+struct specinfo {
+       struct  vnode **si_hashchain;
+       struct  vnode *si_specnext;
+       long    si_flags;
+       dev_t   si_rdev;
+};
+/*
+ * Exported shorthand
+ */
+#define v_rdev v_specinfo->si_rdev
+#define v_hashchain v_specinfo->si_hashchain
+#define v_specnext v_specinfo->si_specnext
+#define v_specflags v_specinfo->si_flags
+
+/*
+ * Flags for specinfo
+ */
+#define        SI_MOUNTEDON    0x0001  /* block special device is mounted on */
+
+/*
+ * Special device management
+ */
+#define        SPECHSZ 64
+#if    ((SPECHSZ&(SPECHSZ-1)) == 0)
+#define        SPECHASH(rdev)  (((rdev>>5)+(rdev))&(SPECHSZ-1))
+#else
+#define        SPECHASH(rdev)  (((unsigned)((rdev>>5)+(rdev)))%SPECHSZ)
+#endif
+
+struct vnode *speclisth[SPECHSZ];
+
+/*
+ * Prototypes for special file operations on vnodes.
+ */
+struct nameidata;
+struct ucred;
+struct flock;
+struct buf;
+struct uio;
+
+int    spec_badop(),
+       spec_ebadf();
+
+int    spec_lookup __P((
+               struct vnode *vp,
+               struct nameidata *ndp,
+               struct proc *p));
+#define spec_create ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) spec_badop)
+#define spec_mknod ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) spec_badop)
+int    spec_open __P((
+               struct vnode *vp,
+               int mode,
+               struct ucred *cred,
+               struct proc *p));
+int    spec_close __P((
+               struct vnode *vp,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+#define spec_access ((int (*) __P(( \
+               struct vnode *vp, \
+               int mode, \
+               struct ucred *cred, \
+               struct proc *p))) spec_ebadf)
+#define spec_getattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) spec_ebadf)
+#define spec_setattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) spec_ebadf)
+int    spec_read __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+int    spec_write __P((
+               struct vnode *vp,
+               struct uio *uio,
+               int ioflag,
+               struct ucred *cred));
+int    spec_ioctl __P((
+               struct vnode *vp,
+               int command,
+               caddr_t data,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+int    spec_select __P((
+               struct vnode *vp,
+               int which,
+               int fflags,
+               struct ucred *cred,
+               struct proc *p));
+#define spec_mmap ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               struct proc *p))) spec_badop)
+#define spec_fsync ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               int waitfor, \
+               struct proc *p))) nullop)
+#define spec_seek ((int (*) __P(( \
+               struct vnode *vp, \
+               off_t oldoff, \
+               off_t newoff, \
+               struct ucred *cred))) spec_badop)
+#define spec_remove ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) spec_badop)
+#define spec_link ((int (*) __P(( \
+               struct vnode *vp, \
+               struct nameidata *ndp, \
+               struct proc *p))) spec_badop)
+#define spec_rename ((int (*) __P(( \
+               struct nameidata *fndp, \
+               struct nameidata *tdnp, \
+               struct proc *p))) spec_badop)
+#define spec_mkdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) spec_badop)
+#define spec_rmdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) spec_badop)
+#define spec_symlink ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               char *target, \
+               struct proc *p))) spec_badop)
+#define spec_readdir ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred, \
+               int *eofflagp))) spec_badop)
+#define spec_readlink ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred))) spec_badop)
+#define spec_abortop ((int (*) __P(( \
+               struct nameidata *ndp))) spec_badop)
+#define spec_inactive ((int (*) __P(( \
+               struct vnode *vp, \
+               struct proc *p))) nullop)
+#define spec_reclaim ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+int    spec_lock __P((
+               struct vnode *vp));
+int    spec_unlock __P((
+               struct vnode *vp));
+int    spec_bmap __P((
+               struct vnode *vp,
+               daddr_t bn,
+               struct vnode **vpp,
+               daddr_t *bnp));
+int    spec_strategy __P((
+               struct buf *bp));
+int    spec_print __P((
+               struct vnode *vp));
+#define spec_islocked ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+int    spec_advlock __P((
+               struct vnode *vp,
+               caddr_t id,
+               int op,
+               struct flock *fl,
+               int flags));
diff --git a/usr/src/sys.386bsd/sys/stat.h b/usr/src/sys.386bsd/sys/stat.h
new file mode 100644 (file)
index 0000000..52948f3
--- /dev/null
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)stat.h      7.11 (Berkeley) 3/3/91
+ */
+
+struct stat
+{
+       dev_t   st_dev;                 /* inode's device */
+       ino_t   st_ino;                 /* inode's number */
+       mode_t  st_mode;                /* inode protection mode */
+       nlink_t st_nlink;               /* number of hard links */
+       uid_t   st_uid;                 /* user ID of the file's owner */
+       gid_t   st_gid;                 /* group ID of the file's group */
+       dev_t   st_rdev;                /* device type */
+       off_t   st_size;                /* file size, in bytes */
+       time_t  st_atime;               /* time of last access */
+       long    st_spare1;
+       time_t  st_mtime;               /* time of last data modification */
+       long    st_spare2;
+       time_t  st_ctime;               /* time of last file status change */
+       long    st_spare3;
+       long    st_blksize;             /* optimal blocksize for I/O */
+       long    st_blocks;              /* blocks allocated for file */
+       u_long  st_flags;               /* user defined flags for file */
+       u_long  st_gen;                 /* file generation number */
+};
+
+#define        S_ISUID 0004000                 /* set user id on execution */
+#define        S_ISGID 0002000                 /* set group id on execution */
+#ifndef _POSIX_SOURCE
+#define        S_ISTXT 0001000                 /* sticky bit */
+#endif
+
+#define        S_IRWXU 0000700                 /* RWX mask for owner */
+#define        S_IRUSR 0000400                 /* R for owner */
+#define        S_IWUSR 0000200                 /* W for owner */
+#define        S_IXUSR 0000100                 /* X for owner */
+
+#ifndef _POSIX_SOURCE
+#define        S_IREAD         S_IRUSR
+#define        S_IWRITE        S_IWUSR
+#define        S_IEXEC         S_IXUSR
+#endif
+
+#define        S_IRWXG 0000070                 /* RWX mask for group */
+#define        S_IRGRP 0000040                 /* R for group */
+#define        S_IWGRP 0000020                 /* W for group */
+#define        S_IXGRP 0000010                 /* X for group */
+
+#define        S_IRWXO 0000007                 /* RWX mask for other */
+#define        S_IROTH 0000004                 /* R for other */
+#define        S_IWOTH 0000002                 /* W for other */
+#define        S_IXOTH 0000001                 /* X for other */
+
+#ifndef _POSIX_SOURCE
+#define        S_IFMT   0170000                /* type of file */
+#define        S_IFIFO  0010000                /* named pipe (fifo) */
+#define        S_IFCHR  0020000                /* character special */
+#define        S_IFDIR  0040000                /* directory */
+#define        S_IFBLK  0060000                /* block special */
+#define        S_IFREG  0100000                /* regular */
+#define        S_IFLNK  0120000                /* symbolic link */
+#define        S_IFSOCK 0140000                /* socket */
+
+#define        S_ISVTX  0001000                /* save swapped text even after use */
+
+#define S_BLKSIZE      512             /* block size used in the stat struct */
+
+                                       /* 0666 */
+#define        DEFFILEMODE     (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
+#endif
+
+#define        S_ISDIR(m)      ((m & 0170000) == 0040000)      /* directory */
+#define        S_ISCHR(m)      ((m & 0170000) == 0020000)      /* char special */
+#define        S_ISBLK(m)      ((m & 0170000) == 0060000)      /* block special */
+#define        S_ISREG(m)      ((m & 0170000) == 0100000)      /* regular file */
+#define        S_ISFIFO(m)     ((m & 0170000) == 0010000)      /* fifo */
+#ifndef _POSIX_SOURCE
+#define        S_ISLNK(m)      ((m & 0170000) == 0120000)      /* symbolic link */
+#define        S_ISSOCK(m)     ((m & 0170000) == 0140000)      /* socket */
+#endif
+
+#ifndef KERNEL
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+mode_t umask __P((mode_t));
+int    chmod __P((const char *, mode_t));
+int    fstat __P((int, struct stat *));
+int    mkdir __P((const char *, mode_t));
+int    mkfifo __P((const char *, mode_t));
+int    stat __P((const char *, struct stat *));
+#ifndef _POSIX_SOURCE
+int    fchmod __P((int, mode_t));
+int    lstat __P((const char *, struct stat *));
+#endif /* not POSIX */
+__END_DECLS
+#endif
diff --git a/usr/src/sys.386bsd/sys/syscall.h b/usr/src/sys.386bsd/sys/syscall.h
new file mode 100644 (file)
index 0000000..f4c2c90
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * System call numbers.
+ *
+ * DO NOT EDIT-- this file is automatically generated.
+ * created from        @(#)syscalls.master     7.26 (Berkeley) 3/25/91
+ */
+
+#define        SYS_exit        1
+#define        SYS_fork        2
+#define        SYS_read        3
+#define        SYS_write       4
+#define        SYS_open        5
+#define        SYS_close       6
+#define        SYS_wait4       7
+                               /* 8 is old creat */
+#define        SYS_link        9
+#define        SYS_unlink      10
+                               /* 11 is obsolete execv */
+#define        SYS_chdir       12
+#define        SYS_fchdir      13
+#define        SYS_mknod       14
+#define        SYS_chmod       15
+#define        SYS_chown       16
+#define        SYS_break       17
+#define        SYS_getfsstat   18
+#define        SYS_lseek       19
+#define        SYS_getpid      20
+#define        SYS_mount       21
+#define        SYS_unmount     22
+#define        SYS_setuid      23
+#define        SYS_getuid      24
+#define        SYS_geteuid     25
+#define        SYS_ptrace      26
+#define        SYS_recvmsg     27
+#define        SYS_sendmsg     28
+#define        SYS_recvfrom    29
+#define        SYS_accept      30
+#define        SYS_getpeername 31
+#define        SYS_getsockname 32
+#define        SYS_access      33
+#define        SYS_chflags     34
+#define        SYS_fchflags    35
+#define        SYS_sync        36
+#define        SYS_kill        37
+#define        SYS_stat        38
+#define        SYS_getppid     39
+#define        SYS_lstat       40
+#define        SYS_dup 41
+#define        SYS_pipe        42
+#define        SYS_getegid     43
+#define        SYS_profil      44
+#define        SYS_ktrace      45
+#define        SYS_sigaction   46
+#define        SYS_getgid      47
+#define        SYS_sigprocmask 48
+#define        SYS_getlogin    49
+#define        SYS_setlogin    50
+#define        SYS_acct        51
+#define        SYS_sigpending  52
+#define        SYS_sigaltstack 53
+#define        SYS_ioctl       54
+#define        SYS_reboot      55
+#define        SYS_revoke      56
+#define        SYS_symlink     57
+#define        SYS_readlink    58
+#define        SYS_execve      59
+#define        SYS_umask       60
+#define        SYS_chroot      61
+#define        SYS_fstat       62
+#define        SYS_getkerninfo 63
+#define        SYS_getpagesize 64
+#define        SYS_msync       65
+#define        SYS_vfork       66
+                               /* 67 is obsolete vread */
+                               /* 68 is obsolete vwrite */
+#define        SYS_sbrk        69
+#define        SYS_sstk        70
+#define        SYS_mmap        71
+#define        SYS_vadvise     72
+#define        SYS_munmap      73
+#define        SYS_mprotect    74
+#define        SYS_madvise     75
+                               /* 76 is obsolete vhangup */
+                               /* 77 is obsolete vlimit */
+#define        SYS_mincore     78
+#define        SYS_getgroups   79
+#define        SYS_setgroups   80
+#define        SYS_getpgrp     81
+#define        SYS_setpgid     82
+#define        SYS_setitimer   83
+                               /* 84 is old wait */
+#define        SYS_swapon      85
+#define        SYS_getitimer   86
+#define        SYS_gethostname 87
+#define        SYS_sethostname 88
+#define        SYS_getdtablesize       89
+#define        SYS_dup2        90
+#define        SYS_fcntl       92
+#define        SYS_select      93
+#define        SYS_fsync       95
+#define        SYS_setpriority 96
+#define        SYS_socket      97
+#define        SYS_connect     98
+                               /* 99 is old accept */
+#define        SYS_getpriority 100
+                               /* 101 is old send */
+                               /* 102 is old recv */
+#define        SYS_sigreturn   103
+#define        SYS_bind        104
+#define        SYS_setsockopt  105
+#define        SYS_listen      106
+                               /* 107 is obsolete vtimes */
+                               /* 108 is old sigvec */
+                               /* 109 is old sigblock */
+                               /* 110 is old sigsetmask */
+#define        SYS_sigsuspend  111
+#define        SYS_sigstack    112
+                               /* 113 is old recvmsg */
+                               /* 114 is old sendmsg */
+#define        SYS_vtrace      115
+                               /* 115 is obsolete vtrace */
+#define        SYS_gettimeofday        116
+#define        SYS_getrusage   117
+#define        SYS_getsockopt  118
+#define        SYS_resuba      119
+#define        SYS_readv       120
+#define        SYS_writev      121
+#define        SYS_settimeofday        122
+#define        SYS_fchown      123
+#define        SYS_fchmod      124
+                               /* 125 is old recvfrom */
+#define        SYS_setreuid    126     /* compatibility; still used by libc */
+#define        SYS_setregid    127     /* compatibility; still used by libc */
+#define        SYS_rename      128
+#define        SYS_truncate    129
+#define        SYS_ftruncate   130
+#define        SYS_flock       131
+#define        SYS_mkfifo      132
+#define        SYS_sendto      133
+#define        SYS_shutdown    134
+#define        SYS_socketpair  135
+#define        SYS_mkdir       136
+#define        SYS_rmdir       137
+#define        SYS_utimes      138
+                               /* 139 is obsolete 4.2 sigreturn */
+#define        SYS_adjtime     140
+                               /* 141 is old getpeername */
+#define        SYS_gethostid   142
+#define        SYS_sethostid   143
+#define        SYS_getrlimit   144
+#define        SYS_setrlimit   145
+                               /* 146 is old killpg */
+#define        SYS_setsid      147
+#define        SYS_quotactl    148
+                               /* 149 is old quota */
+                               /* 150 is old getsockname */
+#define        SYS_nfssvc      155
+#define        SYS_getdirentries       156
+#define        SYS_statfs      157
+#define        SYS_fstatfs     158
+#define        SYS_async_daemon        160
+#define        SYS_getfh       161
+#define        SYS_shmsys      171
+#define        SYS_setgid      181
+#define        SYS_setegid     182
+#define        SYS_seteuid     183
diff --git a/usr/src/sys.386bsd/sys/syslimits.h b/usr/src/sys.386bsd/sys/syslimits.h
new file mode 100644 (file)
index 0000000..6ef56e3
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)syslimits.h 7.4 (Berkeley) 2/4/91
+ */
+
+#define        ARG_MAX         20480   /* max bytes for an exec function */
+#define        CHILD_MAX       40      /* max simultaneous processes */
+#define        LINK_MAX        32767   /* max file link count */
+#define        MAX_CANON       255     /* max bytes in terminal canonical input line */
+#define        MAX_INPUT       255     /* max bytes in terminal input */
+#define        NAME_MAX        255     /* max number of bytes in a file name */
+#define        NGROUPS_MAX     16      /* max number of supplemental group id's */
+#define        OPEN_MAX        64      /* max open files per process */
+#define        PATH_MAX        1024    /* max number of bytes in pathname */
+#define        PIPE_BUF        512     /* max number of bytes for atomic pipe writes */
+
+#define        BC_BASE_MAX     99      /* max ibase/obase values allowed by bc(1) */
+#define        BC_DIM_MAX      2048    /* max array elements allowed by bc(1) */
+#define        BC_SCALE_MAX    99      /* max scale value allowed by bc(1) */
+#define        BC_STRING_MAX   1000    /* max const string length allowed by bc(1) */
+#define        EQUIV_CLASS_MAX 2       /* max weights for order keyword; see locale */
+#define        EXPR_NEST_MAX   32      /* max expressions nested in expr(1) */
+#define        LINE_MAX        2048    /* max length in bytes of an input line */
+#define        RE_DUP_MAX      255     /* max repeated RE's using interval notation */
diff --git a/usr/src/sys.386bsd/sys/syslog.h b/usr/src/sys.386bsd/sys/syslog.h
new file mode 100644 (file)
index 0000000..f5635da
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)syslog.h    7.20 (Berkeley) 2/23/91
+ */
+
+#define        _PATH_LOG       "/dev/log"
+
+/*
+ * priorities/facilities are encoded into a single 32-bit quantity, where the
+ * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
+ * (0-big number).  Both the priorities and the facilities map roughly
+ * one-to-one to strings in the syslogd(8) source code.  This mapping is
+ * included in this file.
+ *
+ * priorities (these are ordered)
+ */
+#define        LOG_EMERG       0       /* system is unusable */
+#define        LOG_ALERT       1       /* action must be taken immediately */
+#define        LOG_CRIT        2       /* critical conditions */
+#define        LOG_ERR         3       /* error conditions */
+#define        LOG_WARNING     4       /* warning conditions */
+#define        LOG_NOTICE      5       /* normal but significant condition */
+#define        LOG_INFO        6       /* informational */
+#define        LOG_DEBUG       7       /* debug-level messages */
+
+#define        LOG_PRIMASK     0x07    /* mask to extract priority part (internal) */
+                               /* extract priority */
+#define        LOG_PRI(p)      ((p) & LOG_PRIMASK)
+#define        LOG_MAKEPRI(fac, pri)   (((fac) << 3) | (pri))
+
+#ifdef SYSLOG_NAMES
+#define        INTERNAL_NOPRI  0x10    /* the "no priority" priority */
+                               /* mark "facility" */
+#define        INTERNAL_MARK   LOG_MAKEPRI(LOG_NFACILITIES, 0)
+typedef struct _code {
+       char    *c_name;
+       int     c_val;
+} CODE;
+
+CODE prioritynames[] = {
+       "alert",        LOG_ALERT,
+       "crit",         LOG_CRIT,
+       "debug",        LOG_DEBUG,
+       "emerg",        LOG_EMERG,
+       "err",          LOG_ERR,
+       "error",        LOG_ERR,                /* DEPRECATED */
+       "info",         LOG_INFO,
+       "none",         INTERNAL_NOPRI,         /* INTERNAL */
+       "notice",       LOG_NOTICE,
+       "panic",        LOG_EMERG,              /* DEPRECATED */
+       "warn",         LOG_WARNING,            /* DEPRECATED */
+       "warning",      LOG_WARNING,
+       NULL,           -1,
+};
+#endif
+
+/* facility codes */
+#define        LOG_KERN        (0<<3)  /* kernel messages */
+#define        LOG_USER        (1<<3)  /* random user-level messages */
+#define        LOG_MAIL        (2<<3)  /* mail system */
+#define        LOG_DAEMON      (3<<3)  /* system daemons */
+#define        LOG_AUTH        (4<<3)  /* security/authorization messages */
+#define        LOG_SYSLOG      (5<<3)  /* messages generated internally by syslogd */
+#define        LOG_LPR         (6<<3)  /* line printer subsystem */
+#define        LOG_NEWS        (7<<3)  /* network news subsystem */
+#define        LOG_UUCP        (8<<3)  /* UUCP subsystem */
+#define        LOG_CRON        (9<<3)  /* clock daemon */
+#define        LOG_AUTHPRIV    (10<<3) /* security/authorization messages (private) */
+
+       /* other codes through 15 reserved for system use */
+#define        LOG_LOCAL0      (16<<3) /* reserved for local use */
+#define        LOG_LOCAL1      (17<<3) /* reserved for local use */
+#define        LOG_LOCAL2      (18<<3) /* reserved for local use */
+#define        LOG_LOCAL3      (19<<3) /* reserved for local use */
+#define        LOG_LOCAL4      (20<<3) /* reserved for local use */
+#define        LOG_LOCAL5      (21<<3) /* reserved for local use */
+#define        LOG_LOCAL6      (22<<3) /* reserved for local use */
+#define        LOG_LOCAL7      (23<<3) /* reserved for local use */
+
+#define        LOG_NFACILITIES 24      /* current number of facilities */
+#define        LOG_FACMASK     0x03f8  /* mask to extract facility part */
+                               /* facility of pri */
+#define        LOG_FAC(p)      (((p) & LOG_FACMASK) >> 3)
+
+#ifdef SYSLOG_NAMES
+CODE facilitynames[] = {
+       "auth",         LOG_AUTH,
+       "authpriv",     LOG_AUTHPRIV,
+       "cron",         LOG_CRON,
+       "daemon",       LOG_DAEMON,
+       "kern",         LOG_KERN,
+       "lpr",          LOG_LPR,
+       "mail",         LOG_MAIL,
+       "mark",         INTERNAL_MARK,          /* INTERNAL */
+       "news",         LOG_NEWS,
+       "security",     LOG_AUTH,               /* DEPRECATED */
+       "syslog",       LOG_SYSLOG,
+       "user",         LOG_USER,
+       "uucp",         LOG_UUCP,
+       "local0",       LOG_LOCAL0,
+       "local1",       LOG_LOCAL1,
+       "local2",       LOG_LOCAL2,
+       "local3",       LOG_LOCAL3,
+       "local4",       LOG_LOCAL4,
+       "local5",       LOG_LOCAL5,
+       "local6",       LOG_LOCAL6,
+       "local7",       LOG_LOCAL7,
+       NULL,           -1,
+};
+#endif
+
+#ifdef KERNEL
+#define        LOG_PRINTF      -1      /* pseudo-priority to indicate use of printf */
+#endif
+
+/*
+ * arguments to setlogmask.
+ */
+#define        LOG_MASK(pri)   (1 << (pri))            /* mask for one priority */
+#define        LOG_UPTO(pri)   ((1 << ((pri)+1)) - 1)  /* all priorities through pri */
+
+/*
+ * Option flags for openlog.
+ *
+ * LOG_ODELAY no longer does anything.
+ * LOG_NDELAY is the inverse of what it used to be.
+ */
+#define        LOG_PID         0x01    /* log the pid with each message */
+#define        LOG_CONS        0x02    /* log on the console if errors in sending */
+#define        LOG_ODELAY      0x04    /* delay open until first syslog() (default) */
+#define        LOG_NDELAY      0x08    /* don't delay open */
+#define        LOG_NOWAIT      0x10    /* don't wait for console forks: DEPRECATED */
+#define        LOG_PERROR      0x20    /* log to stderr as well */
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+#include <stdarg.h>
+
+__BEGIN_DECLS
+void   closelog __P((void));
+void   openlog __P((const char *, int, int));
+int    setlogmask __P((int));
+void   syslog __P((int, const char *, ...));
+void   vsyslog __P((int, const char *, va_list));
+__END_DECLS
+
+#endif /* !KERNEL */
diff --git a/usr/src/sys.386bsd/sys/systm.h b/usr/src/sys.386bsd/sys/systm.h
new file mode 100644 (file)
index 0000000..03340bc
--- /dev/null
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 1982, 1988, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)systm.h     7.17 (Berkeley) 5/25/91
+ */
+
+extern char *panicstr;         /* panic message */
+extern char version[];         /* system version */
+extern char copyright[];       /* system copyright */
+
+extern int nblkdev;            /* number of entries in bdevsw */
+extern int nchrdev;            /* number of entries in cdevsw */
+extern int nswdev;             /* number of swap devices */
+extern int nswap;              /* size of swap space */
+
+extern int selwait;            /* select timeout address */
+
+extern u_char curpri;          /* priority of current process */
+
+extern int maxmem;             /* max memory per process */
+extern int physmem;            /* physical memory */
+
+extern dev_t dumpdev;          /* dump device */
+extern long dumplo;            /* offset into dumpdev */
+
+extern dev_t rootdev;          /* root device */
+extern struct vnode *rootvp;   /* vnode equivalent to above */
+
+extern dev_t swapdev;          /* swapping device */
+extern struct vnode *swapdev_vp;/* vnode equivalent to above */
+
+extern struct sysent {         /* system call table */
+       int     sy_narg;        /* number of arguments */
+       int     (*sy_call)();   /* implementing function */
+} sysent[];
+
+extern int boothowto;          /* reboot flags, from console subsystem */
+#ifdef KADB
+extern char *bootesym;         /* end of symbol info from boot */
+#endif
+
+/* casts to keep lint happy */
+#define        insque(q,p)     _insque((caddr_t)q,(caddr_t)p)
+#define        remque(q)       _remque((caddr_t)q)
+
+/*
+ * General function declarations.
+ */
+int    nullop __P((void));
+int    enodev __P((void));
+int    enoioctl __P((void));
+int    enxio __P((void));
+int    eopnotsupp __P((void));
+int    seltrue __P((dev_t dev, int which, struct proc *p));
+
+void   panic __P((char *));
+void   tablefull __P((char *));
+void   addlog __P((const char *, ...));
+void   log __P((int, const char *, ...));
+void   printf __P((const char *, ...));
+int    sprintf __P((char *buf, const char *, ...));
+void   ttyprintf __P((struct tty *, const char *, ...));
+
+void   bcopy __P((void *from, void *to, u_int len));
+void   ovbcopy __P((void *from, void *to, u_int len));
+void   bzero __P((void *buf, u_int len));
+int    bcmp __P((void *str1, void *str2, u_int len));
+int    strlen __P((char *string));
+
+int    copystr __P((void *kfaddr, void *kdaddr, u_int len, u_int *done));
+int    copyinstr __P((void *udaddr, void *kaddr, u_int len, u_int *done));
+int    copyoutstr __P((void *kaddr, void *udaddr, u_int len, u_int *done));
+int    copyin __P((void *udaddr, void *kaddr, u_int len));
+int    copyout __P((void *kaddr, void *udaddr, u_int len));
+
+int    fubyte __P((void *base));
+#ifdef notdef
+int    fuibyte __P((void *base));
+#endif
+int    subyte __P((void *base, int byte));
+int    suibyte __P((void *base, int byte));
+int    fuword __P((void *base));
+int    fuiword __P((void *base));
+int    suword __P((void *base, int word));
+int    suiword __P((void *base, int word));
+
+int    scanc __P((unsigned size, u_char *cp, u_char *table, int mask));
+int    skpc __P((int mask, int size, char *cp));
+int    locc __P((int mask, char *cp, unsigned size));
+int    ffs __P((long value));
diff --git a/usr/src/sys.386bsd/sys/tablet.h b/usr/src/sys.386bsd/sys/tablet.h
new file mode 100644 (file)
index 0000000..e364ce1
--- /dev/null
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tablet.h    7.5 (Berkeley) 2/15/91
+ */
+
+#ifndef _TABLET_H_
+#define        _TABLET_H_
+
+/*
+ * Tablet line discipline.
+ */
+#ifdef KERNEL
+#include "../h/ioctl.h"
+#else
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * Reads on the tablet return one of the following structures, depending on
+ * the underlying tablet type.  The first two are defined such that a read of
+ * sizeof (gtcopos) on a non-gtco tablet will return meaningful info.  The
+ * in-proximity bit is simulated where the tablet does not directly provide
+ * the information.
+ */
+struct tbpos {
+       int     xpos, ypos;     /* raw x-y coordinates */
+       short   status;         /* buttons/pen down */
+#define        TBINPROX        0100000         /* pen in proximity of tablet */
+       short   scount;         /* sample count */
+};
+
+struct gtcopos {
+       int     xpos, ypos;     /* raw x-y coordinates */
+       short   status;         /* as above */
+       short   scount;         /* sample count */
+       short   xtilt, ytilt;   /* raw tilt */
+       short   pressure;
+       short   pad;            /* pad to longword boundary */
+};
+
+struct polpos {
+       short   p_x, p_y, p_z;  /* raw 3-space coordinates */
+       short   p_azi, p_pit, p_rol;    /* azimuth, pitch, and roll */
+       short   p_stat;         /* status, as above */
+       char    p_key;          /* calculator input keyboard */
+};
+
+#define BIOSMODE       _IOW('b', 1, int)       /* set mode bit(s) */
+#define BIOGMODE       _IOR('b', 2, int)       /* get mode bit(s) */
+#define        TBMODE          0xfff0          /* mode bits: */
+#define                TBPOINT         0x0010          /* single point */
+#define                TBRUN           0x0000          /* runs contin. */
+#define                TBSTOP          0x0020          /* shut-up */
+#define                TBGO            0x0000          /* ~TBSTOP */
+#define        TBTYPE          0x000f          /* tablet type: */
+#define                TBUNUSED        0x0
+#define                TBHITACHI       0x1             /* hitachi tablet */
+#define                TBTIGER         0x2             /* hitachi tiger */
+#define                TBGTCO          0x3             /* gtco */
+#define                TBPOL           0x4             /* polhemus 3space */
+#define                TBHDG           0x5             /* hdg-1111b, low res */
+#define                TBHDGHIRES      0x6             /* hdg-1111b, high res */
+#define                TBDIGI          0x7             /* gtco digi-pad, low res */
+#define                TBDIGIHIRES     0x8             /* gtco digi-pad, high res */
+#define BIOSTYPE       _IOW('b', 3, int)       /* set tablet type */
+#define BIOGTYPE       _IOR('b', 4, int)       /* get tablet type*/
+#endif
+
+#endif /* !_TABLET_H_ */
diff --git a/usr/src/sys.386bsd/sys/termios.h b/usr/src/sys.386bsd/sys/termios.h
new file mode 100644 (file)
index 0000000..649b9cd
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 1988, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)termios.h   7.22 (Berkeley) 5/7/91
+ */
+
+/*
+ *  termios structure
+ */
+#ifndef _TERMIOS_H_
+#define _TERMIOS_H_
+
+/* 
+ * Special Control Characters 
+ *
+ * Index into c_cc[] character array.
+ *
+ *     Name         Subscript  Enabled by 
+ */
+#define        VEOF            0       /* ICANON */
+#define        VEOL            1       /* ICANON */
+#ifndef _POSIX_SOURCE
+#define        VEOL2           2       /* ICANON */
+#endif
+#define        VERASE          3       /* ICANON */
+#ifndef _POSIX_SOURCE
+#define VWERASE        4       /* ICANON */
+#endif 
+#define VKILL          5       /* ICANON */
+#ifndef _POSIX_SOURCE
+#define        VREPRINT        6       /* ICANON */
+#endif
+/*                     7          spare 1 */
+#define VINTR          8       /* ISIG */
+#define VQUIT          9       /* ISIG */
+#define VSUSP          10      /* ISIG */
+#ifndef _POSIX_SOURCE
+#define VDSUSP         11      /* ISIG */
+#endif
+#define VSTART         12      /* IXON, IXOFF */
+#define VSTOP          13      /* IXON, IXOFF */
+#ifndef _POSIX_SOURCE
+#define        VLNEXT          14      /* IEXTEN */
+#define        VDISCARD        15      /* IEXTEN */
+#endif
+#define VMIN           16      /* !ICANON */
+#define VTIME          17      /* !ICANON */
+#ifndef _POSIX_SOURCE
+#define VSTATUS                18      /* ICANON */
+/*                     19         spare 2 */
+#define        NCCS            20
+#endif
+
+#define _POSIX_VDISABLE        ((unsigned char)'\377')
+
+#ifndef _POSIX_SOURCE
+#define CCEQ(val, c)   (c == val ? val != _POSIX_VDISABLE : 0)
+#endif
+
+/*
+ * Input flags - software input processing
+ */
+#define        IGNBRK          0x00000001      /* ignore BREAK condition */
+#define        BRKINT          0x00000002      /* map BREAK to SIGINTR */
+#define        IGNPAR          0x00000004      /* ignore (discard) parity errors */
+#define        PARMRK          0x00000008      /* mark parity and framing errors */
+#define        INPCK           0x00000010      /* enable checking of parity errors */
+#define        ISTRIP          0x00000020      /* strip 8th bit off chars */
+#define        INLCR           0x00000040      /* map NL into CR */
+#define        IGNCR           0x00000080      /* ignore CR */
+#define        ICRNL           0x00000100      /* map CR to NL (ala CRMOD) */
+#define        IXON            0x00000200      /* enable output flow control */
+#define        IXOFF           0x00000400      /* enable input flow control */
+#ifndef _POSIX_SOURCE
+#define        IXANY           0x00000800      /* any char will restart after stop */
+#define IMAXBEL                0x00002000      /* ring bell on input queue full */
+#endif  /*_POSIX_SOURCE */
+
+/*
+ * Output flags - software output processing
+ */
+#define        OPOST           0x00000001      /* enable following output processing */
+#ifndef _POSIX_SOURCE
+#define ONLCR          0x00000002      /* map NL to CR-NL (ala CRMOD) */
+#define OXTABS         0x00000004      /* expand tabs to spaces */
+#define ONOEOT         0x00000008      /* discard EOT's (^D) on output) */
+#endif  /*_POSIX_SOURCE */
+
+/*
+ * Control flags - hardware control of terminal
+ */
+#ifndef _POSIX_SOURCE
+#define        CIGNORE         0x00000001      /* ignore control flags */
+#endif
+#define CSIZE          0x00000300      /* character size mask */
+#define     CS5                    0x00000000      /* 5 bits (pseudo) */
+#define     CS6                    0x00000100      /* 6 bits */
+#define     CS7                    0x00000200      /* 7 bits */
+#define     CS8                    0x00000300      /* 8 bits */
+#define CSTOPB         0x00000400      /* send 2 stop bits */
+#define CREAD          0x00000800      /* enable receiver */
+#define PARENB         0x00001000      /* parity enable */
+#define PARODD         0x00002000      /* odd parity, else even */
+#define HUPCL          0x00004000      /* hang up on last close */
+#define CLOCAL         0x00008000      /* ignore modem status lines */
+#ifndef _POSIX_SOURCE
+#define CCTS_OFLOW     0x00010000      /* CTS flow control of output */
+#define CRTSCTS                CCTS_OFLOW      /* ??? */
+#define CRTS_IFLOW     0x00020000      /* RTS flow control of input */
+#define        MDMBUF          0x00100000      /* flow control output via Carrier */
+#endif
+
+
+/* 
+ * "Local" flags - dumping ground for other state
+ *
+ * Warning: some flags in this structure begin with
+ * the letter "I" and look like they belong in the
+ * input flag.
+ */
+
+#ifndef _POSIX_SOURCE
+#define        ECHOKE          0x00000001      /* visual erase for line kill */
+#endif  /*_POSIX_SOURCE */
+#define        ECHOE           0x00000002      /* visually erase chars */
+#define        ECHOK           0x00000004      /* echo NL after line kill */
+#define ECHO           0x00000008      /* enable echoing */
+#define        ECHONL          0x00000010      /* echo NL even if ECHO is off */
+#ifndef _POSIX_SOURCE
+#define        ECHOPRT         0x00000020      /* visual erase mode for hardcopy */
+#define ECHOCTL        0x00000040      /* echo control chars as ^(Char) */
+#endif  /*_POSIX_SOURCE */
+#define        ISIG            0x00000080      /* enable signals INTR, QUIT, [D]SUSP */
+#define        ICANON          0x00000100      /* canonicalize input lines */
+#ifndef _POSIX_SOURCE
+#define ALTWERASE      0x00000200      /* use alternate WERASE algorithm */
+#endif  /*_POSIX_SOURCE */
+#define        IEXTEN          0x00000400      /* enable DISCARD and LNEXT */
+#define EXTPROC         0x00000800      /* external processing */
+#define TOSTOP         0x00400000      /* stop background jobs from output */
+#ifndef _POSIX_SOURCE
+#define FLUSHO         0x00800000      /* output being flushed (state) */
+#define        NOKERNINFO      0x02000000      /* no kernel output from VSTATUS */
+#define PENDIN         0x20000000      /* XXX retype pending input (state) */
+#endif  /*_POSIX_SOURCE */
+#define        NOFLSH          0x80000000      /* don't flush after interrupt */
+
+typedef unsigned long  tcflag_t;
+typedef unsigned char  cc_t;
+typedef long           speed_t;
+
+struct termios {
+       tcflag_t        c_iflag;        /* input flags */
+       tcflag_t        c_oflag;        /* output flags */
+       tcflag_t        c_cflag;        /* control flags */
+       tcflag_t        c_lflag;        /* local flags */
+       cc_t            c_cc[NCCS];     /* control chars */
+       long            c_ispeed;       /* input speed */
+       long            c_ospeed;       /* output speed */
+};
+
+/* 
+ * Commands passed to tcsetattr() for setting the termios structure.
+ */
+#define        TCSANOW         0               /* make change immediate */
+#define        TCSADRAIN       1               /* drain output, then change */
+#define        TCSAFLUSH       2               /* drain output, flush input */
+#ifndef _POSIX_SOURCE
+#define TCSASOFT       0x10            /* flag - don't alter h.w. state */
+#endif
+
+/*
+ * Standard speeds
+ */
+#define B0     0
+#define B50    50
+#define B75    75
+#define B110   110
+#define B134   134
+#define B150   150
+#define B200   200
+#define B300   300
+#define B600   600
+#define B1200  1200
+#define        B1800   1800
+#define B2400  2400
+#define B4800  4800
+#define B9600  9600
+#define B19200 19200
+#define B38400 38400
+#ifndef _POSIX_SOURCE
+#define EXTA   19200
+#define EXTB   38400
+#endif  /*_POSIX_SOURCE */
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+speed_t        cfgetispeed __P((const struct termios *));
+speed_t        cfgetospeed __P((const struct termios *));
+int    cfsetispeed __P((struct termios *, speed_t));
+int    cfsetospeed __P((struct termios *, speed_t));
+int    tcdrain __P((int));
+int    tcflow __P((int, int));
+int    tcflush __P((int, int));
+int    tcgetattr __P((int, struct termios *));
+int    tcsendbreak __P((int, int));
+int    tcsetattr __P((int, int, const struct termios *));
+
+#define        TCIFLUSH        1
+#define        TCOFLUSH        2
+#define TCIOFLUSH      3
+#define        TCOOFF          1
+#define        TCOON           2
+#define TCIOFF         3
+#define TCION          4
+
+#ifndef _POSIX_SOURCE
+void   cfmakeraw __P((struct termios *));
+void   cfsetspeed __P((struct termios *, speed_t));
+#endif /* !POSIX */
+__END_DECLS
+
+#endif /* !KERNEL */
+
+/*
+ * END OF PROTECTED INCLUDE.
+ */
+#endif /* !_TERMIOS_H_ */
+
+#ifndef _POSIX_SOURCE
+#ifdef KERNEL
+#include "ttydefaults.h"
+#else
+#include <sys/ttydefaults.h>
+#endif
+#endif  /*_POSIX_SOURCE */
diff --git a/usr/src/sys.386bsd/sys/time.h b/usr/src/sys.386bsd/sys/time.h
new file mode 100644 (file)
index 0000000..4f12085
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)time.h      7.6 (Berkeley) 2/22/91
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+struct timeval {
+       long    tv_sec;         /* seconds */
+       long    tv_usec;        /* and microseconds */
+};
+
+struct timezone {
+       int     tz_minuteswest; /* minutes west of Greenwich */
+       int     tz_dsttime;     /* type of dst correction */
+};
+#define        DST_NONE        0       /* not on dst */
+#define        DST_USA         1       /* USA style dst */
+#define        DST_AUST        2       /* Australian style dst */
+#define        DST_WET         3       /* Western European dst */
+#define        DST_MET         4       /* Middle European dst */
+#define        DST_EET         5       /* Eastern European dst */
+#define        DST_CAN         6       /* Canada */
+
+/*
+ * Operations on timevals.
+ *
+ * NB: timercmp does not work for >= or <=.
+ */
+#define        timerisset(tvp)         ((tvp)->tv_sec || (tvp)->tv_usec)
+#define        timercmp(tvp, uvp, cmp) \
+       ((tvp)->tv_sec cmp (uvp)->tv_sec || \
+        (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+#define        timerclear(tvp)         (tvp)->tv_sec = (tvp)->tv_usec = 0
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define        ITIMER_REAL     0
+#define        ITIMER_VIRTUAL  1
+#define        ITIMER_PROF     2
+
+struct itimerval {
+       struct  timeval it_interval;    /* timer interval */
+       struct  timeval it_value;       /* current value */
+};
+
+#ifndef KERNEL
+#include <time.h>
+
+#ifndef _POSIX_SOURCE
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    adjtime __P((const struct timeval *, struct timeval *));
+int    getitimer __P((int, struct itimerval *));
+int    gettimeofday __P((struct timeval *, struct timezone *));
+int    setitimer __P((int, const struct itimerval *, struct itimerval *));
+int    settimeofday __P((const struct timeval *, const struct timezone *));
+int    utimes __P((const char *, const struct timeval *));
+__END_DECLS
+#endif /* !POSIX */
+
+#endif /* !KERNEL */
+
+#endif /* !_SYS_TIME_H_ */
diff --git a/usr/src/sys.386bsd/sys/timeb.h b/usr/src/sys.386bsd/sys/timeb.h
new file mode 100644 (file)
index 0000000..6e04845
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)timeb.h     7.2 (Berkeley) 5/5/91
+ */
+
+/* The ftime(2) system call structure -- deprecated. */
+struct timeb {
+       time_t  time;                   /* seconds since the Epoch */
+       unsigned short millitm;         /* + milliseconds since the Epoch */
+       short   timezone;               /* minutes west of CUT */
+       short   dstflag;                /* DST == non-zero */
+};
diff --git a/usr/src/sys.386bsd/sys/times.h b/usr/src/sys.386bsd/sys/times.h
new file mode 100644 (file)
index 0000000..52ce6fa
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)times.h     7.6 (Berkeley) 3/9/91
+ */
+
+#include <machine/ansi.h>
+
+#ifdef _CLOCK_T_
+typedef        _CLOCK_T_       clock_t;
+#undef _CLOCK_T_
+#endif
+
+struct tms {
+       clock_t tms_utime;      /* User CPU time */
+       clock_t tms_stime;      /* System CPU time */
+       clock_t tms_cutime;     /* User CPU time of terminated child procs */
+       clock_t tms_cstime;     /* System CPU time of terminated child procs */
+};
+
+#ifndef KERNEL
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+clock_t        times __P((struct tms *));
+__END_DECLS
+#endif
diff --git a/usr/src/sys.386bsd/sys/tprintf.h b/usr/src/sys.386bsd/sys/tprintf.h
new file mode 100644 (file)
index 0000000..3bb8dad
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tprintf.h   7.2 (Berkeley) 5/4/91
+ */
+
+typedef struct session *tpr_t;
+
+tpr_t  tprintf_open __P((struct proc *));
+void   tprintf_close __P((tpr_t));
+
+void   tprintf __P((tpr_t, const char *fmt, ...));
diff --git a/usr/src/sys.386bsd/sys/trace.h b/usr/src/sys.386bsd/sys/trace.h
new file mode 100644 (file)
index 0000000..573d3fb
--- /dev/null
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)trace.h     7.6 (Berkeley) 5/5/91
+ */
+
+/*
+ * File system buffer tracing points; all trace <pack(dev, size), bn>
+ */
+#define        TR_BREADHIT     0       /* buffer read found in cache */
+#define        TR_BREADMISS    1       /* buffer read not in cache */
+#define        TR_BWRITE       2       /* buffer written */
+#define        TR_BREADHITRA   3       /* buffer read-ahead found in cache */
+#define        TR_BREADMISSRA  4       /* buffer read-ahead not in cache */
+#define        TR_XFODMISS     5       /* exe fod read */
+#define        TR_XFODHIT      6       /* exe fod read */
+#define        TR_BRELSE       7       /* brelse */
+#define        TR_BREALLOC     8       /* expand/contract a buffer */
+
+/*
+ * Memory allocator trace points; all trace the amount of memory involved
+ */
+#define        TR_MALL         10      /* memory allocated */
+
+/*
+ * Paging trace points: all are <vaddr, pid>
+ */
+#define        TR_INTRANS      20      /* page intransit block */
+#define        TR_EINTRANS     21      /* page intransit wait done */
+#define        TR_FRECLAIM     22      /* reclaim from free list */
+#define        TR_RECLAIM      23      /* reclaim from loop */
+#define        TR_XSFREC       24      /* reclaim from free list instead of drum */
+#define        TR_XIFREC       25      /* reclaim from free list instead of fsys */
+#define        TR_WAITMEM      26      /* wait for memory in pagein */
+#define        TR_EWAITMEM     27      /* end memory wait in pagein */
+#define        TR_ZFOD         28      /* zfod page fault */
+#define        TR_EXFOD        29      /* exec fod page fault */
+#define        TR_VRFOD        30      /* vread fod page fault */
+#define        TR_CACHEFOD     31      /* fod in file system cache */
+#define        TR_SWAPIN       32      /* drum page fault */
+#define        TR_PGINDONE     33      /* page in done */
+#define        TR_SWAPIO       34      /* swap i/o request arrives */
+
+/*
+ * System call trace points.
+ */
+#define        TR_VADVISE      40      /* vadvise occurred with <arg, pid> */
+
+/*
+ * Miscellaneous
+ */
+#define        TR_STAMP        45      /* user said vtrace(VTR_STAMP, value); */
+
+/*
+ * This defines the size of the trace flags array.
+ */
+#define        TR_NFLAGS       100     /* generous */
+
+#define        TRCSIZ          4096
+
+/*
+ * Specifications of the vtrace() system call, which takes one argument.
+ */
+#define        VTRACE          64+51
+
+#define        VTR_DISABLE     0               /* set a trace flag to 0 */
+#define        VTR_ENABLE      1               /* set a trace flag to 1 */
+#define        VTR_VALUE       2               /* return value of a trace flag */
+#define        VTR_UALARM      3               /* set alarm to go off (sig 16) */
+                                       /* in specified number of hz */
+#define        VTR_STAMP       4               /* user specified stamp */
+
+#ifdef KERNEL
+#ifdef TRACE
+char   traceflags[TR_NFLAGS];
+struct proc *traceproc;
+int    tracebuf[TRCSIZ];
+unsigned tracex;
+int    tracewhich;
+#define        pack(v,b)       (((v)->v_mount->mnt_stat.f_fsid.val[0])<<16)|(b)
+#define        trace(a,b,c)    if (traceflags[a]) trace1(a,b,c)
+#else
+#define        trace(a,b,c)    ;
+#endif
+#endif
diff --git a/usr/src/sys.386bsd/sys/ttychars.h b/usr/src/sys.386bsd/sys/ttychars.h
new file mode 100644 (file)
index 0000000..27bb20c
--- /dev/null
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ttychars.h  7.6 (Berkeley) 5/9/91
+ */
+
+/*
+ * 4.3 COMPATIBILITY FILE
+ *
+ * User visible structures and constants related to terminal handling.
+ */
+#ifndef _TTYCHARS_H_
+#define        _TTYCHARS_H_
+
+struct ttychars {
+       char    tc_erase;       /* erase last character */
+       char    tc_kill;        /* erase entire line */
+       char    tc_intrc;       /* interrupt */
+       char    tc_quitc;       /* quit */
+       char    tc_startc;      /* start output */
+       char    tc_stopc;       /* stop output */
+       char    tc_eofc;        /* end-of-file */
+       char    tc_brkc;        /* input delimiter (like nl) */
+       char    tc_suspc;       /* stop process signal */
+       char    tc_dsuspc;      /* delayed stop process signal */
+       char    tc_rprntc;      /* reprint line */
+       char    tc_flushc;      /* flush output (toggles) */
+       char    tc_werasc;      /* word erase */
+       char    tc_lnextc;      /* literal next character */
+};
+#ifdef USE_OLD_TTY
+#include <sys/ttydefaults.h>   /* to pick up character defaults */
+#endif
+#endif /* !_TTYCHARS_H_ */
diff --git a/usr/src/sys.386bsd/sys/ttydefaults.h b/usr/src/sys.386bsd/sys/ttydefaults.h
new file mode 100644 (file)
index 0000000..97a9dff
--- /dev/null
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ttydefaults.h       7.9 (Berkeley) 5/9/91
+ */
+
+/*
+ * System wide defaults for terminal state.
+ */
+#ifndef _TTYDEFAULTS_H_
+#define        _TTYDEFAULTS_H_
+
+/*
+ * Defaults on "first" open.
+ */
+#define        TTYDEF_IFLAG    (BRKINT | ISTRIP | ICRNL | IMAXBEL | IXON | IXANY)
+#define TTYDEF_OFLAG   (OPOST | ONLCR | OXTABS)
+#define TTYDEF_LFLAG   (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL)
+#define TTYDEF_CFLAG   (CREAD | CS7 | PARENB | HUPCL)
+#define TTYDEF_SPEED   (B9600)
+
+/*
+ * Control Character Defaults
+ */
+#define CTRL(x)        (x&037)
+#define        CEOF            CTRL('d')
+#define        CEOL            ((unsigned)'\377')      /* XXX avoid _POSIX_VDISABLE */
+#define        CERASE          0177
+#define        CINTR           CTRL('c')
+#define        CSTATUS         ((unsigned)'\377')      /* XXX avoid _POSIX_VDISABLE */
+#define        CKILL           CTRL('u')
+#define        CMIN            1
+#define        CQUIT           034             /* FS, ^\ */
+#define        CSUSP           CTRL('z')
+#define        CTIME           0
+#define        CDSUSP          CTRL('y')
+#define        CSTART          CTRL('q')
+#define        CSTOP           CTRL('s')
+#define        CLNEXT          CTRL('v')
+#define        CDISCARD        CTRL('o')
+#define        CWERASE         CTRL('w')
+#define        CREPRINT        CTRL('r')
+#define        CEOT            CEOF
+/* compat */
+#define        CBRK            CEOL
+#define CRPRNT         CREPRINT
+#define        CFLUSH          CDISCARD
+
+/* PROTECTED INCLUSION ENDS HERE */
+#endif /* !_TTYDEFAULTS_H_ */
+
+/*
+ * #define TTYDEFCHARS to include an array of default control characters.
+ */
+#ifdef TTYDEFCHARS
+cc_t   ttydefchars[NCCS] = {
+       CEOF,   CEOL,   CEOL,   CERASE, CWERASE, CKILL, CREPRINT, 
+       _POSIX_VDISABLE, CINTR, CQUIT,  CSUSP,  CDSUSP, CSTART, CSTOP,  CLNEXT,
+       CDISCARD, CMIN, CTIME,  CSTATUS, _POSIX_VDISABLE
+};
+#undef TTYDEFCHARS
+#endif /* TTYDEFCHARS */
diff --git a/usr/src/sys.386bsd/sys/ttydev.h b/usr/src/sys.386bsd/sys/ttydev.h
new file mode 100644 (file)
index 0000000..84b6d38
--- /dev/null
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ttydev.h    7.8 (Berkeley) 5/9/91
+ */
+
+/* COMPATABILITY HEADER FILE */
+
+#ifndef _TTYDEV_H_
+#define        _TTYDEV_H_
+
+#ifdef USE_OLD_TTY
+#define B0     0
+#define B50    1
+#define B75    2
+#define B110   3
+#define B134   4
+#define B150   5
+#define B200   6
+#define B300   7
+#define B600   8
+#define B1200  9
+#define        B1800   10
+#define B2400  11
+#define B4800  12
+#define B9600  13
+#define EXTA   14
+#define EXTB   15
+#endif /* USE_OLD_TTY */
+
+#endif /* !_TTYDEV_H_ */
diff --git a/usr/src/sys.386bsd/sys/types.h b/usr/src/sys.386bsd/sys/types.h
new file mode 100644 (file)
index 0000000..937219f
--- /dev/null
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)types.h     7.17 (Berkeley) 5/6/91
+ */
+
+#ifndef _TYPES_H_
+#define        _TYPES_H_
+
+typedef        unsigned char   u_char;
+typedef        unsigned short  u_short;
+typedef        unsigned int    u_int;
+typedef        unsigned long   u_long;
+typedef        unsigned short  ushort;         /* Sys V compatibility */
+
+typedef        char *  caddr_t;                /* core address */
+typedef        long    daddr_t;                /* disk address */
+typedef        short   dev_t;                  /* device number */
+typedef        u_long  ino_t;                  /* inode number */
+typedef        long    off_t;                  /* file offset (should be a quad) */
+typedef        u_short nlink_t;                /* link count */
+typedef        long    swblk_t;                /* swap offset */
+typedef        long    segsz_t;                /* segment size */
+typedef        u_short uid_t;                  /* user id */
+typedef        u_short gid_t;                  /* group id */
+typedef        short   pid_t;                  /* process id */
+typedef        u_short mode_t;                 /* permissions */
+typedef u_long fixpt_t;                /* fixed point number */
+
+#ifndef _POSIX_SOURCE
+typedef        struct  _uquad  { u_long val[2]; } u_quad;
+typedef        struct  _quad   {   long val[2]; } quad;
+typedef        long *  qaddr_t;        /* should be typedef quad * qaddr_t; */
+
+#define        major(x)        ((int)(((u_int)(x) >> 8)&0xff)) /* major number */
+#define        minor(x)        ((int)((x)&0xff))               /* minor number */
+#define        makedev(x,y)    ((dev_t)(((x)<<8) | (y)))       /* create dev_t */
+#endif
+
+#include <machine/ansi.h>
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#include <machine/types.h>
+#endif
+
+#ifdef _CLOCK_T_
+typedef        _CLOCK_T_       clock_t;
+#undef _CLOCK_T_
+#endif
+
+#ifdef _SIZE_T_
+typedef        _SIZE_T_        size_t;
+#undef _SIZE_T_
+#endif
+
+#ifdef _TIME_T_
+typedef        _TIME_T_        time_t;
+#undef _TIME_T_
+#endif
+
+#ifndef _POSIX_SOURCE
+#define        NBBY    8               /* number of bits in a byte */
+
+/*
+ * Select uses bit masks of file descriptors in longs.  These macros
+ * manipulate such bit fields (the filesystem macros use chars).
+ * FD_SETSIZE may be defined by the user, but the default here should
+ * be enough for most uses.
+ */
+#ifndef        FD_SETSIZE
+#define        FD_SETSIZE      256
+#endif
+
+typedef long   fd_mask;
+#define NFDBITS        (sizeof(fd_mask) * NBBY)        /* bits per mask */
+
+#ifndef howmany
+#define        howmany(x, y)   (((x)+((y)-1))/(y))
+#endif
+
+typedef        struct fd_set {
+       fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+
+#define        FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define        FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define        FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define        FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
+
+#if defined(__STDC__) && defined(KERNEL)
+/*
+ * Forward structure declarations for function prototypes.
+ * We include the common structures that cross subsystem boundaries here;
+ * others are mostly used in the same place that the structure is defined.
+ */
+struct proc;
+struct pgrp;
+struct ucred;
+struct rusage;
+struct file;
+struct buf;
+struct tty;
+struct uio;
+#endif
+
+#endif /* !_POSIX_SOURCE */
+#endif /* !_TYPES_H_ */
diff --git a/usr/src/sys.386bsd/sys/ucred.h b/usr/src/sys.386bsd/sys/ucred.h
new file mode 100644 (file)
index 0000000..3e99505
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ucred.h     7.5 (Berkeley) 2/5/91
+ */
+
+#ifndef _UCRED_H_
+#define        _UCRED_H_
+
+/*
+ * Credentials.
+ */
+struct ucred {
+       u_short cr_ref;                 /* reference count */
+       uid_t   cr_uid;                 /* effective user id */
+       short   cr_ngroups;             /* number of groups */
+       gid_t   cr_groups[NGROUPS];     /* groups */
+};
+#define cr_gid cr_groups[0]
+#define NOCRED ((struct ucred *)-1)
+
+#ifdef KERNEL
+#define        crhold(cr)      (cr)->cr_ref++
+struct ucred *crget();
+struct ucred *crcopy();
+struct ucred *crdup();
+#endif KERNEL
+
+#endif /* !_UCRED_H_ */
diff --git a/usr/src/sys.386bsd/sys/uio.h b/usr/src/sys.386bsd/sys/uio.h
new file mode 100644 (file)
index 0000000..30d315e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)uio.h       7.8 (Berkeley) 4/15/91
+ */
+
+#ifndef _UIO_H_
+#define        _UIO_H_
+
+struct iovec {
+       caddr_t iov_base;
+       int     iov_len;
+};
+
+enum   uio_rw { UIO_READ, UIO_WRITE };
+
+/*
+ * Segment flag values.
+ */
+enum   uio_seg {
+       UIO_USERSPACE,          /* from user data space */
+       UIO_SYSSPACE,           /* from system space */
+       UIO_USERISPACE          /* from user I space */
+};
+
+struct uio {
+       struct  iovec *uio_iov;
+       int     uio_iovcnt;
+       off_t   uio_offset;
+       int     uio_resid;
+       enum    uio_seg uio_segflg;
+       enum    uio_rw uio_rw;
+       struct  proc *uio_procp;
+};
+
+ /*
+  * Limits
+  */
+#define UIO_MAXIOV     1024            /* max 1K of iov's */
+#define UIO_SMALLIOV   8               /* 8 on stack, else malloc */
+
+#ifndef        KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    readv __P((int, const struct iovec *, int));
+int    writev __P((int, const struct iovec *, int));
+__END_DECLS
+
+#endif /* !KERNEL */
+
+#endif /* !_UIO_H_ */
diff --git a/usr/src/sys.386bsd/sys/un.h b/usr/src/sys.386bsd/sys/un.h
new file mode 100644 (file)
index 0000000..4458781
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)un.h        7.7 (Berkeley) 6/28/90
+ */
+
+/*
+ * Definitions for UNIX IPC domain.
+ */
+struct sockaddr_un {
+       u_char  sun_len;                /* sockaddr len including null */
+       u_char  sun_family;             /* AF_UNIX */
+       char    sun_path[104];          /* path name (gag) */
+};
+
+#ifdef KERNEL
+int    unp_discard();
+#else
+
+/* actual length of an initialized sockaddr_un */
+#define SUN_LEN(su) \
+       (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
diff --git a/usr/src/sys.386bsd/sys/unistd.h b/usr/src/sys.386bsd/sys/unistd.h
new file mode 100644 (file)
index 0000000..4d3460a
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)unistd.h    5.14 (Berkeley) 4/1/91
+ */
+
+#ifndef _SYS_UNISTD_H_
+#define        _SYS_UNISTD_H_
+
+/* compile-time symbolic constants */
+#define        _POSIX_JOB_CONTROL      /* implementation supports job control */
+#ifdef _NOTYET
+#define        _POSIX_SAVED_IDS        /* saved set-user-ID and set-group-ID */
+#endif
+#define        _POSIX_VERSION          198808L
+
+/* execution-time symbolic constants */
+#define        _POSIX_CHOWN_RESTRICTED /* chown requires appropriate privileges */
+#define        _POSIX_NO_TRUNC         /* too-long path components generate errors */
+                               /* may disable terminal special characters */
+#define        _POSIX_VDISABLE ((unsigned char)'\377')
+
+/* access function */
+#define        F_OK            0       /* test for existence of file */
+#define        X_OK            0x01    /* test for execute or search permission */
+#define        W_OK            0x02    /* test for write permission */
+#define        R_OK            0x04    /* test for read permission */
+
+/* whence values for lseek(2) */
+#define        SEEK_SET        0       /* set file offset to offset */
+#define        SEEK_CUR        1       /* set file offset to current plus offset */
+#define        SEEK_END        2       /* set file offset to EOF plus offset */
+
+#ifndef _POSIX_SOURCE
+/* whence values for lseek(2); renamed by POSIX 1003.1 */
+#define        L_SET           SEEK_SET
+#define        L_INCR          SEEK_CUR
+#define        L_XTND          SEEK_END
+#endif
+
+/* configurable pathname variables */
+#define        _PC_LINK_MAX            1
+#define        _PC_MAX_CANON           2
+#define        _PC_MAX_INPUT           3
+#define        _PC_NAME_MAX            4
+#define        _PC_PATH_MAX            5
+#define        _PC_PIPE_BUF            6
+#define        _PC_CHOWN_RESTRICTED    7
+#define        _PC_NO_TRUNC            8
+#define        _PC_VDISABLE            9
+
+/* configurable system variables */
+#define        _SC_ARG_MAX             1
+#define        _SC_CHILD_MAX           2
+#define        _SC_CLK_TCK             3
+#define        _SC_NGROUPS_MAX         4
+#define        _SC_OPEN_MAX            5
+#define        _SC_JOB_CONTROL         6
+#define        _SC_SAVED_IDS           7
+#define        _SC_VERSION             8
+
+#endif /* !_SYS_UNISTD_H_ */
diff --git a/usr/src/sys.386bsd/sys/unpcb.h b/usr/src/sys.386bsd/sys/unpcb.h
new file mode 100644 (file)
index 0000000..f7014ff
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)unpcb.h     7.6 (Berkeley) 6/28/90
+ */
+
+/*
+ * Protocol control block for an active
+ * instance of a UNIX internal protocol.
+ *
+ * A socket may be associated with an vnode in the
+ * file system.  If so, the unp_vnode pointer holds
+ * a reference count to this vnode, which should be irele'd
+ * when the socket goes away.
+ *
+ * A socket may be connected to another socket, in which
+ * case the control block of the socket to which it is connected
+ * is given by unp_conn.
+ *
+ * A socket may be referenced by a number of sockets (e.g. several
+ * sockets may be connected to a datagram socket.)  These sockets
+ * are in a linked list starting with unp_refs, linked through
+ * unp_nextref and null-terminated.  Note that a socket may be referenced
+ * by a number of other sockets and may also reference a socket (not
+ * necessarily one which is referencing it).  This generates
+ * the need for unp_refs and unp_nextref to be separate fields.
+ *
+ * Stream sockets keep copies of receive sockbuf sb_cc and sb_mbcnt
+ * so that changes in the sockbuf may be computed to modify
+ * back pressure on the sender accordingly.
+ */
+struct unpcb {
+       struct  socket *unp_socket;     /* pointer back to socket */
+       struct  vnode *unp_vnode;       /* if associated with file */
+       ino_t   unp_ino;                /* fake inode number */
+       struct  unpcb *unp_conn;        /* control block of connected socket */
+       struct  unpcb *unp_refs;        /* referencing socket linked list */
+       struct  unpcb *unp_nextref;     /* link in unp_refs list */
+       struct  mbuf *unp_addr;         /* bound address of socket */
+       int     unp_cc;                 /* copy of rcv.sb_cc */
+       int     unp_mbcnt;              /* copy of rcv.sb_mbcnt */
+};
+
+#define        sotounpcb(so)   ((struct unpcb *)((so)->so_pcb))
diff --git a/usr/src/sys.386bsd/sys/user.h b/usr/src/sys.386bsd/sys/user.h
new file mode 100644 (file)
index 0000000..b175752
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)user.h      7.19 (Berkeley) 5/4/91
+ */
+
+#include <machine/pcb.h>
+#ifndef KERNEL
+/* stuff that *used* to be included by user.h, or is now needed */
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/ucred.h>
+#include <sys/uio.h>
+#endif
+#include <sys/resourcevar.h>
+#include <sys/signalvar.h>
+#include <vm/vm.h>             /* XXX */
+#include <sys/kinfo_proc.h>
+
+
+/*
+ * Per process structure containing data that isn't needed in core
+ * when the process isn't running (esp. when swapped out).
+ * This structure may or may not be at the same kernel address
+ * in all processes.
+ */
+struct user {
+       struct  pcb u_pcb;
+
+       struct  sigacts u_sigacts;      /* p_sigacts points here (use it!) */
+       struct  pstats u_stats;         /* p_stats points here (use it!) */
+
+       /*
+        * Remaining fields only for core dump and/or ptrace--
+        * not valid at other times!
+        */
+       struct  kinfo_proc u_kproc;     /* proc + eproc */
+};
+
+/*
+ * Redefinitions to make the debuggers happy for now...
+ * This subterfuge brought to you by coredump() and procxmt().
+ * These fields are *only* valid at those times!
+ */
+#define        U_ar0   u_kproc.kp_proc.p_regs  /* copy of curproc->p_regs */
+#define        U_tsize u_kproc.kp_eproc.e_vm.vm_tsize
+#define        U_dsize u_kproc.kp_eproc.e_vm.vm_dsize
+#define        U_ssize u_kproc.kp_eproc.e_vm.vm_ssize
+#define        U_sig   u_sigacts.ps_sig
+#define        U_code  u_sigacts.ps_code
+
+#ifndef KERNEL
+#define        u_ar0   U_ar0
+#define        u_tsize U_tsize
+#define        u_dsize U_dsize
+#define        u_ssize U_ssize
+#define        u_sig   U_sig
+#define        u_code  U_code
+#endif /* KERNEL */
diff --git a/usr/src/sys.386bsd/sys/vadvise.h b/usr/src/sys.386bsd/sys/vadvise.h
new file mode 100644 (file)
index 0000000..71ae785
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vadvise.h   7.2 (Berkeley) 5/5/91
+ */
+
+/*
+ * Parameters to vadvise() to tell system of particular paging
+ * behaviour:
+ *     VA_NORM         Normal strategy
+ *     VA_ANOM         Sampling page behaviour is not a win, don't bother
+ *                     Suitable during GCs in LISP, or sequential or random
+ *                     page referencing.
+ *     VA_SEQL         Sequential behaviour expected.
+ *     VA_FLUSH        Invalidate all page table entries.
+ */
+#define        VA_NORM         0
+#define        VA_ANOM         1
+#define        VA_SEQL         2
+#define        VA_FLUSH        3
diff --git a/usr/src/sys.386bsd/sys/vcmd.h b/usr/src/sys.386bsd/sys/vcmd.h
new file mode 100644 (file)
index 0000000..8057499
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vcmd.h      7.4 (Berkeley) 5/5/91
+ */
+
+#include <sys/ioctl.h>
+
+#define        VPRINT          0100
+#define        VPLOT           0200
+#define        VPRINTPLOT      0400
+
+#define        VGETSTATE       _IOR('v', 0, int)
+#define        VSETSTATE       _IOW('v', 1, int)
diff --git a/usr/src/sys.386bsd/sys/vlimit.h b/usr/src/sys.386bsd/sys/vlimit.h
new file mode 100644 (file)
index 0000000..1306818
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vlimit.h    7.2 (Berkeley) 5/5/91
+ */
+
+/*
+ * Limits for u.u_limit[i], per process, inherited.
+ */
+#define        LIM_NORAISE     0       /* if <> 0, can't raise limits */
+#define        LIM_CPU         1       /* max secs cpu time */
+#define        LIM_FSIZE       2       /* max size of file created */
+#define        LIM_DATA        3       /* max growth of data space */
+#define        LIM_STACK       4       /* max growth of stack */
+#define        LIM_CORE        5       /* max size of ``core'' file */
+#define        LIM_MAXRSS      6       /* max desired data+stack core usage */
+
+#define        NLIMITS         6
+
+#define        INFINITY        0x7fffffff
diff --git a/usr/src/sys.386bsd/sys/vmmeter.h b/usr/src/sys.386bsd/sys/vmmeter.h
new file mode 100644 (file)
index 0000000..99cd4eb
--- /dev/null
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vmmeter.h   7.3 (Berkeley) 5/5/91
+ */
+
+/*
+ * Virtual memory related instrumentation
+ */
+struct vmmeter
+{
+#define        v_first v_swtch
+       unsigned v_swtch;       /* context switches */
+       unsigned v_trap;        /* calls to trap */
+       unsigned v_syscall;     /* calls to syscall() */
+       unsigned v_intr;        /* device interrupts */
+       unsigned v_soft;        /* software interrupts */
+       unsigned v_pdma;        /* pseudo-dma interrupts */
+       unsigned v_pswpin;      /* pages swapped in */
+       unsigned v_pswpout;     /* pages swapped out */
+       unsigned v_pgin;        /* pageins */
+       unsigned v_pgout;       /* pageouts */
+       unsigned v_pgpgin;      /* pages paged in */
+       unsigned v_pgpgout;     /* pages paged out */
+       unsigned v_intrans;     /* intransit blocking page faults */
+       unsigned v_pgrec;       /* total page reclaims */
+       unsigned v_xsfrec;      /* found in free list rather than on swapdev */
+       unsigned v_xifrec;      /* found in free list rather than in filsys */
+       unsigned v_exfod;       /* pages filled on demand from executables */
+       unsigned v_zfod;        /* pages zero filled on demand */
+       unsigned v_vrfod;       /* fills of pages mapped by vread() */
+       unsigned v_nexfod;      /* number of exfod's created */
+       unsigned v_nzfod;       /* number of zfod's created */
+       unsigned v_nvrfod;      /* number of vrfod's created */
+       unsigned v_pgfrec;      /* page reclaims from free list */
+       unsigned v_faults;      /* total faults taken */
+       unsigned v_scan;        /* scans in page out daemon */
+       unsigned v_rev;         /* revolutions of the hand */
+       unsigned v_seqfree;     /* pages taken from sequential programs */
+       unsigned v_dfree;       /* pages freed by daemon */
+       unsigned v_fastpgrec;   /* fast reclaims in locore */
+#ifdef tahoe
+       unsigned v_fpe;         /* floating point emulation traps */
+       unsigned v_align;       /* alignment emulation traps */
+#endif
+#define        v_last v_fastpgrec
+       unsigned v_swpin;       /* swapins */
+       unsigned v_swpout;      /* swapouts */
+};
+#ifdef KERNEL
+struct vmmeter cnt, rate, sum;
+#endif
+
+/* systemwide totals computed every five seconds */
+struct vmtotal
+{
+       short   t_rq;           /* length of the run queue */
+       short   t_dw;           /* jobs in ``disk wait'' (neg priority) */
+       short   t_pw;           /* jobs in page wait */
+       short   t_sl;           /* jobs sleeping in core */
+       short   t_sw;           /* swapped out runnable/short block jobs */
+       long    t_vm;           /* total virtual memory */
+       long    t_avm;          /* active virtual memory */
+       long    t_rm;           /* total real memory in use */
+       long    t_arm;          /* active real memory */
+       long    t_vmtxt;        /* virtual memory used by text */
+       long    t_avmtxt;       /* active virtual memory used by text */
+       long    t_rmtxt;        /* real memory used by text */
+       long    t_armtxt;       /* active real memory used by text */
+       long    t_free;         /* free memory pages */
+};
+#ifdef KERNEL
+struct vmtotal total;
+#endif
+
+/*
+ * Optional instrumentation.
+ */
+#ifdef PGINPROF
+
+#define        NDMON   128
+#define        NSMON   128
+
+#define        DRES    20
+#define        SRES    5
+
+#define        PMONMIN 20
+#define        PRES    50
+#define        NPMON   64
+
+#define        RMONMIN 130
+#define        RRES    5
+#define        NRMON   64
+
+/* data and stack size distribution counters */
+unsigned int   dmon[NDMON+1];
+unsigned int   smon[NSMON+1];
+
+/* page in time distribution counters */
+unsigned int   pmon[NPMON+2];
+
+/* reclaim time distribution counters */
+unsigned int   rmon[NRMON+2];
+
+int    pmonmin;
+int    pres;
+int    rmonmin;
+int    rres;
+
+unsigned rectime;              /* accumulator for reclaim times */
+unsigned pgintime;             /* accumulator for page in times */
+#endif
diff --git a/usr/src/sys.386bsd/sys/vnode.h b/usr/src/sys.386bsd/sys/vnode.h
new file mode 100644 (file)
index 0000000..42b202b
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vnode.h     7.39 (Berkeley) 6/27/91
+ */
+
+#ifndef KERNEL
+#include <machine/endian.h>
+#endif
+
+/*
+ * The vnode is the focus of all file activity in UNIX.
+ * There is a unique vnode allocated for each active file,
+ * each current directory, each mounted-on file, text file, and the root.
+ */
+
+/*
+ * vnode types. VNON means no type.
+ */
+enum vtype     { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD };
+
+/*
+ * Vnode tag types.
+ * These are for the benefit of external programs only (e.g., pstat)
+ * and should NEVER be inspected inside the kernel.
+ */
+enum vtagtype  { VT_NON, VT_UFS, VT_NFS, VT_MFS };
+
+/*
+ * This defines the maximum size of the private data area
+ * permitted for any file system type. A defined constant 
+ * is used rather than a union structure to cut down on the
+ * number of header files that must be included.
+ */
+#define        VN_MAXPRIVATE   188
+
+struct vnode {
+       u_long          v_flag;                 /* vnode flags (see below) */
+       short           v_usecount;             /* reference count of users */
+       short           v_writecount;           /* reference count of writers */
+       long            v_holdcnt;              /* page & buffer references */
+       off_t           v_lastr;                /* last read (read-ahead) */
+       u_long          v_id;                   /* capability identifier */
+       struct mount    *v_mount;               /* ptr to vfs we are in */
+       struct vnodeops *v_op;                  /* vnode operations */
+       struct vnode    *v_freef;               /* vnode freelist forward */
+       struct vnode    **v_freeb;              /* vnode freelist back */
+       struct vnode    *v_mountf;              /* vnode mountlist forward */
+       struct vnode    **v_mountb;             /* vnode mountlist back */
+       struct buf      *v_cleanblkhd;          /* clean blocklist head */
+       struct buf      *v_dirtyblkhd;          /* dirty blocklist head */
+       long            v_numoutput;            /* num of writes in progress */
+       enum vtype      v_type;                 /* vnode type */
+       union {
+               struct mount    *vu_mountedhere;/* ptr to mounted vfs (VDIR) */
+               struct socket   *vu_socket;     /* unix ipc (VSOCK) */
+               caddr_t         vu_vmdata;      /* private data for vm (VREG) */
+               struct specinfo *vu_specinfo;   /* device (VCHR, VBLK) */
+               struct fifoinfo *vu_fifoinfo;   /* fifo (VFIFO) */
+       } v_un;
+       enum vtagtype   v_tag;                  /* type of underlying data */
+       char v_data[VN_MAXPRIVATE];             /* private data for fs */
+};
+#define        v_mountedhere   v_un.vu_mountedhere
+#define        v_socket        v_un.vu_socket
+#define        v_vmdata        v_un.vu_vmdata
+#define        v_specinfo      v_un.vu_specinfo
+#define        v_fifoinfo      v_un.vu_fifoinfo
+
+/*
+ * vnode flags.
+ */
+#define        VROOT           0x0001  /* root of its file system */
+#define        VTEXT           0x0002  /* vnode is a pure text prototype */
+#define        VSYSTEM         0x0004  /* vnode being used by kernel */
+#define        VXLOCK          0x0100  /* vnode is locked to change underlying type */
+#define        VXWANT          0x0200  /* process is waiting for vnode */
+#define        VBWAIT          0x0400  /* waiting for output to complete */
+#define        VALIASED        0x0800  /* vnode has an alias */
+
+/*
+ * Vnode attributes.  A field value of VNOVAL
+ * represents a field whose value is unavailable
+ * (getattr) or which is not to be changed (setattr).
+ */
+struct vattr {
+       enum vtype      va_type;        /* vnode type (for create) */
+       u_short         va_mode;        /* files access mode and type */
+       short           va_nlink;       /* number of references to file */
+       uid_t           va_uid;         /* owner user id */
+       gid_t           va_gid;         /* owner group id */
+       long            va_fsid;        /* file system id (dev for now) */
+       long            va_fileid;      /* file id */
+       u_quad          va_qsize;       /* file size in bytes */
+       long            va_blocksize;   /* blocksize preferred for i/o */
+       struct timeval  va_atime;       /* time of last access */
+       struct timeval  va_mtime;       /* time of last modification */
+       struct timeval  va_ctime;       /* time file changed */
+       u_long          va_gen;         /* generation number of file */
+       u_long          va_flags;       /* flags defined for file */
+       dev_t           va_rdev;        /* device the special file represents */
+       u_quad          va_qbytes;      /* bytes of disk space held by file */
+};
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define        va_size         va_qsize.val[0]
+#define        va_size_rsv     va_qsize.val[1]
+#define        va_bytes        va_qbytes.val[0]
+#define        va_bytes_rsv    va_qbytes.val[1]
+#else
+#define        va_size         va_qsize.val[1]
+#define        va_size_rsv     va_qsize.val[0]
+#define        va_bytes        va_qbytes.val[1]
+#define        va_bytes_rsv    va_qbytes.val[0]
+#endif
+
+/*
+ * Operations on vnodes.
+ */
+#ifdef __STDC__
+struct flock;
+struct nameidata;
+#endif
+
+struct vnodeops {
+       int     (*vop_lookup)   __P((struct vnode *vp, struct nameidata *ndp,
+                                   struct proc *p));
+       int     (*vop_create)   __P((struct nameidata *ndp, struct vattr *vap,
+                                   struct proc *p));
+       int     (*vop_mknod)    __P((struct nameidata *ndp, struct vattr *vap,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_open)     __P((struct vnode *vp, int mode,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_close)    __P((struct vnode *vp, int fflag,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_access)   __P((struct vnode *vp, int mode,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_getattr)  __P((struct vnode *vp, struct vattr *vap,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_setattr)  __P((struct vnode *vp, struct vattr *vap,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_read)     __P((struct vnode *vp, struct uio *uio,
+                                   int ioflag, struct ucred *cred));
+       int     (*vop_write)    __P((struct vnode *vp, struct uio *uio,
+                                   int ioflag, struct ucred *cred));
+       int     (*vop_ioctl)    __P((struct vnode *vp, int command,
+                                   caddr_t data, int fflag,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_select)   __P((struct vnode *vp, int which, int fflags,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_mmap)     __P((struct vnode *vp, int fflags,
+                                   struct ucred *cred, struct proc *p));
+       int     (*vop_fsync)    __P((struct vnode *vp, int fflags,
+                                   struct ucred *cred, int waitfor,
+                                   struct proc *p));
+       int     (*vop_seek)     __P((struct vnode *vp, off_t oldoff,
+                                   off_t newoff, struct ucred *cred));
+       int     (*vop_remove)   __P((struct nameidata *ndp, struct proc *p));
+       int     (*vop_link)     __P((struct vnode *vp, struct nameidata *ndp,
+                                   struct proc *p));
+       int     (*vop_rename)   __P((struct nameidata *fndp,
+                                   struct nameidata *tdnp, struct proc *p));
+       int     (*vop_mkdir)    __P((struct nameidata *ndp, struct vattr *vap,
+                                   struct proc *p));
+       int     (*vop_rmdir)    __P((struct nameidata *ndp, struct proc *p));
+       int     (*vop_symlink)  __P((struct nameidata *ndp, struct vattr *vap,
+                                   char *target, struct proc *p));
+       int     (*vop_readdir)  __P((struct vnode *vp, struct uio *uio,
+                                   struct ucred *cred, int *eofflagp));
+       int     (*vop_readlink) __P((struct vnode *vp, struct uio *uio,
+                                   struct ucred *cred));
+       int     (*vop_abortop)  __P((struct nameidata *ndp));
+       int     (*vop_inactive) __P((struct vnode *vp, struct proc *p));
+       int     (*vop_reclaim)  __P((struct vnode *vp));
+       int     (*vop_lock)     __P((struct vnode *vp));
+       int     (*vop_unlock)   __P((struct vnode *vp));
+       int     (*vop_bmap)     __P((struct vnode *vp, daddr_t bn,
+                                   struct vnode **vpp, daddr_t *bnp));
+       int     (*vop_strategy) __P((struct buf *bp));
+       int     (*vop_print)    __P((struct vnode *vp));
+       int     (*vop_islocked) __P((struct vnode *vp));
+       int     (*vop_advlock)  __P((struct vnode *vp, caddr_t id, int op,
+                                   struct flock *fl, int flags));
+};
+
+/* Macros to call the vnode ops */
+#define        VOP_LOOKUP(v,n,p)       (*((v)->v_op->vop_lookup))(v,n,p)
+#define        VOP_CREATE(n,a,p)       (*((n)->ni_dvp->v_op->vop_create))(n,a,p)
+#define        VOP_MKNOD(n,a,c,p)      (*((n)->ni_dvp->v_op->vop_mknod))(n,a,c,p)
+#define        VOP_OPEN(v,f,c,p)       (*((v)->v_op->vop_open))(v,f,c,p)
+#define        VOP_CLOSE(v,f,c,p)      (*((v)->v_op->vop_close))(v,f,c,p)
+#define        VOP_ACCESS(v,f,c,p)     (*((v)->v_op->vop_access))(v,f,c,p)
+#define        VOP_GETATTR(v,a,c,p)    (*((v)->v_op->vop_getattr))(v,a,c,p)
+#define        VOP_SETATTR(v,a,c,p)    (*((v)->v_op->vop_setattr))(v,a,c,p)
+#define        VOP_READ(v,u,i,c)       (*((v)->v_op->vop_read))(v,u,i,c)
+#define        VOP_WRITE(v,u,i,c)      (*((v)->v_op->vop_write))(v,u,i,c)
+#define        VOP_IOCTL(v,o,d,f,c,p)  (*((v)->v_op->vop_ioctl))(v,o,d,f,c,p)
+#define        VOP_SELECT(v,w,f,c,p)   (*((v)->v_op->vop_select))(v,w,f,c,p)
+#define        VOP_MMAP(v,c,p)         (*((v)->v_op->vop_mmap))(v,c,p)
+#define        VOP_FSYNC(v,f,c,w,p)    (*((v)->v_op->vop_fsync))(v,f,c,w,p)
+#define        VOP_SEEK(v,p,o,w)       (*((v)->v_op->vop_seek))(v,p,o,w)
+#define        VOP_REMOVE(n,p)         (*((n)->ni_dvp->v_op->vop_remove))(n,p)
+#define        VOP_LINK(v,n,p)         (*((n)->ni_dvp->v_op->vop_link))(v,n,p)
+#define        VOP_RENAME(s,t,p)       (*((s)->ni_dvp->v_op->vop_rename))(s,t,p)
+#define        VOP_MKDIR(n,a,p)        (*((n)->ni_dvp->v_op->vop_mkdir))(n,a,p)
+#define        VOP_RMDIR(n,p)          (*((n)->ni_dvp->v_op->vop_rmdir))(n,p)
+#define        VOP_SYMLINK(n,a,m,p)    (*((n)->ni_dvp->v_op->vop_symlink))(n,a,m,p)
+#define        VOP_READDIR(v,u,c,e)    (*((v)->v_op->vop_readdir))(v,u,c,e)
+#define        VOP_READLINK(v,u,c)     (*((v)->v_op->vop_readlink))(v,u,c)
+#define        VOP_ABORTOP(n)          (*((n)->ni_dvp->v_op->vop_abortop))(n)
+#define        VOP_INACTIVE(v,p)       (*((v)->v_op->vop_inactive))(v,p)
+#define        VOP_RECLAIM(v)          (*((v)->v_op->vop_reclaim))(v)
+#define        VOP_LOCK(v)             (*((v)->v_op->vop_lock))(v)
+#define        VOP_UNLOCK(v)           (*((v)->v_op->vop_unlock))(v)
+#define        VOP_BMAP(v,s,p,n)       (*((v)->v_op->vop_bmap))(v,s,p,n)
+#define        VOP_STRATEGY(b)         (*((b)->b_vp->v_op->vop_strategy))(b)
+#define        VOP_PRINT(v)            (*((v)->v_op->vop_print))(v)
+#define        VOP_ISLOCKED(v)         (((v)->v_flag & VXLOCK) || \
+                               (*((v)->v_op->vop_islocked))(v))
+#define        VOP_ADVLOCK(v,p,o,l,f)  (*((v)->v_op->vop_advlock))(v,p,o,l,f)
+
+/*
+ * flags for ioflag
+ */
+#define        IO_UNIT         0x01            /* do I/O as atomic unit */
+#define        IO_APPEND       0x02            /* append write to end */
+#define        IO_SYNC         0x04            /* do I/O synchronously */
+#define        IO_NODELOCKED   0x08            /* underlying node already locked */
+#define        IO_NDELAY       0x10            /* FNDELAY flag set in file table */
+
+/*
+ *  Modes. Some values same as Ixxx entries from inode.h for now
+ */
+#define        VSUID   04000           /* set user id on execution */
+#define        VSGID   02000           /* set group id on execution */
+#define        VSVTX   01000           /* save swapped text even after use */
+#define        VREAD   0400            /* read, write, execute permissions */
+#define        VWRITE  0200
+#define        VEXEC   0100
+
+/*
+ * Token indicating no attribute value yet assigned
+ */
+#define        VNOVAL  ((unsigned)0xffffffff)
+
+#ifdef KERNEL
+/*
+ * public vnode manipulation functions
+ */
+int    vn_open __P((struct nameidata *ndp, struct proc *p, int fmode,
+           int cmode));
+int    vn_close __P((struct vnode *vp, int flags, struct ucred *cred,
+           struct proc *p));
+int    vn_rdwr __P((enum uio_rw rw, struct vnode *vp, caddr_t base,
+           int len, off_t offset, enum uio_seg segflg, int ioflg,
+           struct ucred *cred, int *aresid, struct proc *p));
+int    vn_read __P((struct file *fp, struct uio *uio, struct ucred *cred));
+int    vn_write __P((struct file *fp, struct uio *uio, struct ucred *cred));
+int    vn_ioctl __P((struct file *fp, int com, caddr_t data, struct proc *p));
+int    vn_select __P((struct file *fp, int which, struct proc *p));
+int    vn_closefile __P((struct file *fp, struct proc *p));
+int    getnewvnode __P((enum vtagtype tag, struct mount *mp,
+           struct vnodeops *vops, struct vnode **vpp));
+int    bdevvp __P((int dev, struct vnode **vpp));
+       /* check for special device aliases */
+       /* XXX nvp_rdev should be type dev_t, not int */
+struct         vnode *checkalias __P((struct vnode *vp, int nvp_rdev,
+           struct mount *mp));
+void   vattr_null __P((struct vattr *vap));
+int    vcount __P((struct vnode *vp)); /* total references to a device */
+int    vget __P((struct vnode *vp));   /* get first reference to a vnode */
+void   vref __P((struct vnode *vp));   /* increase reference to a vnode */
+void   vput __P((struct vnode *vp));   /* unlock and release vnode */
+void   vrele __P((struct vnode *vp));  /* release vnode */
+void   vgone __P((struct vnode *vp));  /* completely recycle vnode */
+void   vgoneall __P((struct vnode *vp));/* recycle vnode and all its aliases */
+
+/*
+ * Flags to various vnode functions.
+ */
+#define        SKIPSYSTEM      0x0001          /* vflush: skip vnodes marked VSYSTEM */
+#define        FORCECLOSE      0x0002          /* vflush: force file closeure */
+#define        DOCLOSE         0x0004          /* vclean: close active files */
+
+#ifndef DIAGNOSTIC
+#define        VREF(vp)        (vp)->v_usecount++      /* increase reference */
+#define        VHOLD(vp)       (vp)->v_holdcnt++       /* increase buf or page ref */
+#define        HOLDRELE(vp)    (vp)->v_holdcnt--       /* decrease buf or page ref */
+#define        VATTR_NULL(vap) (*(vap) = va_null)      /* initialize a vattr */
+#else /* DIAGNOSTIC */
+#define        VREF(vp)        vref(vp)
+#define        VHOLD(vp)       vhold(vp)
+#define        HOLDRELE(vp)    holdrele(vp)
+#define        VATTR_NULL(vap) vattr_null(vap)
+#endif
+
+#define        NULLVP  ((struct vnode *)NULL)
+
+/*
+ * Global vnode data.
+ */
+extern struct vnode *rootdir;          /* root (i.e. "/") vnode */
+extern long desiredvnodes;             /* number of vnodes desired */
+extern struct vattr va_null;           /* predefined null vattr structure */
+#endif
diff --git a/usr/src/sys.386bsd/sys/vsio.h b/usr/src/sys.386bsd/sys/vsio.h
new file mode 100644 (file)
index 0000000..e9a78a1
--- /dev/null
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 1987 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vsio.h      7.4 (Berkeley) 5/9/91
+ */
+
+ /****************************************************************************
+ *                                                                         *
+ *  Copyright (c) 1983, 1984 by                                                    *
+ *  DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts.                 *
+ *  All rights reserved.                                                   *
+ *                                                                         *
+ *  This software is furnished on an as-is basis and may be used and copied *
+ *  only with inclusion of the above copyright notice. This software or any *
+ *  other copies thereof may be provided or otherwise made available to     *
+ *  others only for non-commercial purposes.  No title to or ownership of   *
+ *  the software is hereby transferred.                                            *
+ *                                                                         *
+ *  The information in this software is  subject to change without notice   *
+ *  and  should  not  be  construed as  a commitment by DIGITAL EQUIPMENT   *
+ *  CORPORATION.                                                           *
+ *                                                                         *
+ *  DIGITAL assumes no responsibility for the use  or  reliability of its   *
+ *  software on equipment which is not supplied by DIGITAL.                *
+ *                                                                         *
+ *                                                                         *
+ ****************************************************************************/
+/* 
+ * vsio.h - VS100 I/O command definitions
+ * 
+ * Author:     Christopher A. Kent
+ *             Digital Equipment Corporation
+ *             Western Research Lab
+ * Date:       Tue Jun 21 1983
+ */
+
+/* 
+ * Possible ioctl calls
+ */
+
+#define        VSIOINIT        _IO('V', 0)             /* init the device */
+#define        VSIOSTART       _IOW('V', 1, int)       /* start microcode */
+#define        VSIOABORT       _IO('V', 2)             /* abort a command chain */
+#define        VSIOPWRUP       _IO('V', 3)             /* power-up reset */
+#define        VSIOGETVER      _IOR('V', 4, int)       /* get rom version */
+#define        VSIOSYNC        _IO('V', 6)             /* synch with device */
+#define        VSIOBBACTL      _IOW('V', 8, int)       /* control the BBA */
+#define        VSIOFIBCTL      _IOW('V', 9, int)       /* lamp on/off */
+#define        VSIOFIBRETRY    _IOW('V',10, int)       /* fiber retries */
+#define        VSIOGETSTATS    _IOR('V',11, vsStats)   /* get statistics */
+#define        VSIOGETIOA      _IOR('V',13, vsIoAddrAddr)/* get ioreg address */
+#define        VSIOUSERWAIT    _IO('V', 15)    /* wait for user I/O completion */
+#define VSIOWAITGO     _IOW('V', 16, caddr_t)  /* wait then go */
+
+
+#define        VSIO_OFF        0               /* option off */
+#define        VSIO_ON         1               /* option on */
+
+#define        VS_FIB_FINITE   1               /* finite retries */
+#define        VS_FIB_INFINITE 2               /* infinite retries */
+
+/* 
+ * Event queue entries
+ */
+
+typedef struct _vs_event{
+       u_short vse_x;          /* x position */
+       u_short vse_y;          /* y position */
+       u_short vse_time;       /* 10 millisecond units (button only) */
+       char    vse_type;       /* button or motion? */
+       u_char  vse_key;        /* the key (button only) */
+       char    vse_direction;  /* which direction (button only) */
+       char    vse_device;     /* which device (button only) */
+}vsEvent;
+
+#define        VSE_BUTTON      0               /* button moved */
+#define        VSE_MMOTION     1               /* mouse moved */
+#define        VSE_TMOTION     2               /* tablet moved */
+
+#define        VSE_KBTUP       0               /* up */
+#define        VSE_KBTDOWN     1               /* down */
+
+#define        VSE_MOUSE       1               /* mouse */
+#define        VSE_DKB         2               /* main keyboard */
+#define        VSE_TABLET      3               /* graphics tablet */
+#define        VSE_AUX         4               /* auxiliary */
+#define        VSE_CONSOLE     5               /* console */
+
+typedef struct _vsStats{
+       int     errors;                 /* count errors */
+       int     unsolIntr;              /* count unsolicited interrupts */
+       int     overruns;               /* event queue overruns */
+       int     flashes;                /* flashes on fiber link */
+       int     ignites;                /* times turned on */
+       int     douses;                 /* times turned off */
+       int     linkErrors;             /* link errors */
+}vsStats;
+
+typedef struct _vs_cursor{
+       short x;
+       short y;
+}vsCursor;
+
+typedef struct _vs_box {
+       short bottom;
+       short right;
+       short left;
+       short top;
+}vsBox;
+
+typedef struct _vsIoAddr {
+       short    *ioreg;
+       short    status;
+       caddr_t  obuff;
+       int      obufflen;
+       int      reloc;
+       vsEvent  *ibuff;
+       int      iqsize;                /* may assume power of 2 */
+       int      ihead;                 /* atomic write */
+       int      itail;                 /* atomic read */
+       vsCursor mouse;                 /* atomic read/write */
+       vsBox    mbox;                  /* atomic read/write */
+} vsIoAddr;
+typedef vsIoAddr *vsIoAddrAddr;
diff --git a/usr/src/sys.386bsd/sys/vtimes.h b/usr/src/sys.386bsd/sys/vtimes.h
new file mode 100644 (file)
index 0000000..a614568
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vtimes.h    7.2 (Berkeley) 5/5/91
+ */
+
+/*
+ * Structure returned by vtimes() and in vwait().
+ * In vtimes() two of these are returned, one for the process itself
+ * and one for all its children.  In vwait() these are combined
+ * by adding componentwise (except for maxrss, which is max'ed).
+ */
+struct vtimes {
+       int     vm_utime;               /* user time (60'ths) */
+       int     vm_stime;               /* system time (60'ths) */
+       /* divide next two by utime+stime to get averages */
+       unsigned vm_idsrss;             /* integral of d+s rss */
+       unsigned vm_ixrss;              /* integral of text rss */
+       int     vm_maxrss;              /* maximum rss */
+       int     vm_majflt;              /* major page faults */
+       int     vm_minflt;              /* minor page faults */
+       int     vm_nswap;               /* number of swaps */
+       int     vm_inblk;               /* block reads */
+       int     vm_oublk;               /* block writes */
+};
diff --git a/usr/src/sys.386bsd/sys/wait.h b/usr/src/sys.386bsd/sys/wait.h
new file mode 100644 (file)
index 0000000..de3a50d
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)wait.h      7.17 (Berkeley) 6/19/91
+ */
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#ifdef _POSIX_SOURCE
+#define        _W_INT(i)       (i)
+#else
+#define        _W_INT(w)       (*(int *)&(w))  /* convert union wait to int */
+#define        WCOREFLAG       0200
+#endif
+
+#define        _WSTATUS(x)     (_W_INT(x) & 0177)
+#define        _WSTOPPED       0177            /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x)  (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x)    (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x)    (_WSTATUS(x))
+#define WIFEXITED(x)   (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x)   (_W_INT(x) & WCOREFLAG)
+
+#define        W_EXITCODE(ret, sig)    ((ret) << 8 | (sig))
+#define        W_STOPCODE(sig)         ((sig) << 8 | _WSTOPPED)
+#endif
+
+/*
+ * Option bits for the second argument of wait4.  WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0).  WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals.  If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG                1       /* dont hang in wait */
+#define WUNTRACED      2       /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define        WAIT_ANY        (-1)    /* any process */
+#define        WAIT_MYPGRP     0       /* any process in my process group */
+
+#ifndef BYTE_ORDER
+#include <machine/endian.h>
+#endif
+
+/*
+ * Deprecated:
+ * Structure of the information in the status word returned by wait4.
+ * If w_stopval==WSTOPPED, then the second structure describes
+ * the information returned, else the first.
+ */
+union wait {
+       int     w_status;               /* used in syscall */
+       /*
+        * Terminated process status.
+        */
+       struct {
+#if BYTE_ORDER == LITTLE_ENDIAN 
+               unsigned int    w_Termsig:7,    /* termination signal */
+                               w_Coredump:1,   /* core dump indicator */
+                               w_Retcode:8,    /* exit code if w_termsig==0 */
+                               w_Filler:16;    /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN 
+               unsigned int    w_Filler:16,    /* upper bits filler */
+                               w_Retcode:8,    /* exit code if w_termsig==0 */
+                               w_Coredump:1,   /* core dump indicator */
+                               w_Termsig:7;    /* termination signal */
+#endif
+       } w_T;
+       /*
+        * Stopped process status.  Returned
+        * only for traced children unless requested
+        * with the WUNTRACED option bit.
+        */
+       struct {
+#if BYTE_ORDER == LITTLE_ENDIAN 
+               unsigned int    w_Stopval:8,    /* == W_STOPPED if stopped */
+                               w_Stopsig:8,    /* signal that stopped us */
+                               w_Filler:16;    /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN 
+               unsigned int    w_Filler:16,    /* upper bits filler */
+                               w_Stopsig:8,    /* signal that stopped us */
+                               w_Stopval:8;    /* == W_STOPPED if stopped */
+#endif
+       } w_S;
+};
+#define        w_termsig       w_T.w_Termsig
+#define w_coredump     w_T.w_Coredump
+#define w_retcode      w_T.w_Retcode
+#define w_stopval      w_S.w_Stopval
+#define w_stopsig      w_S.w_Stopsig
+
+#define        WSTOPPED        _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#ifndef KERNEL
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t  wait __P((int *));
+pid_t  waitpid __P((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t  wait3 __P((int *, int, struct rusage *));
+pid_t  wait4 __P((pid_t, int *, int, struct rusage *));
+#endif
+__END_DECLS
+#endif
diff --git a/usr/src/sys.386bsd/ufs/dinode.h b/usr/src/sys.386bsd/ufs/dinode.h
new file mode 100644 (file)
index 0000000..599c6a4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1982, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dinode.h    7.10 (Berkeley) 5/8/91
+ */
+
+/*
+ * A dinode contains all the meta-data associated with a UFS file.
+ * This structure defines the on-disk format of a dinode.
+ */
+
+#define        NDADDR  12              /* direct addresses in inode */
+#define        NIADDR  3               /* indirect addresses in inode */
+
+struct dinode {
+       u_short di_mode;        /*  0: mode and type of file */
+       short   di_nlink;       /*  2: number of links to file */
+       uid_t   di_uid;         /*  4: owner's user id */
+       gid_t   di_gid;         /*  6: owner's group id */
+       u_quad  di_qsize;       /*  8: number of bytes in file */
+       time_t  di_atime;       /* 16: time last accessed */
+       long    di_atspare;
+       time_t  di_mtime;       /* 24: time last modified */
+       long    di_mtspare;
+       time_t  di_ctime;       /* 32: last time inode changed */
+       long    di_ctspare;
+       daddr_t di_db[NDADDR];  /* 40: disk block addresses */
+       daddr_t di_ib[NIADDR];  /* 88: indirect blocks */
+       long    di_flags;       /* 100: status, currently unused */
+       long    di_blocks;      /* 104: blocks actually held */
+       long    di_gen;         /* 108: generation number */
+       long    di_spare[4];    /* 112: reserved, currently unused */
+};
+
+#if BYTE_ORDER == LITTLE_ENDIAN || defined(tahoe) /* ugh! -- must be fixed */
+#define        di_size         di_qsize.val[0]
+#else /* BYTE_ORDER == BIG_ENDIAN */
+#define        di_size         di_qsize.val[1]
+#endif
+#define        di_rdev         di_db[0]
+
+/* file modes */
+#define        IFMT            0170000         /* mask of file type */
+#define        IFIFO           0010000         /* named pipe (fifo) */
+#define        IFCHR           0020000         /* character special device */
+#define        IFDIR           0040000         /* directory */
+#define        IFBLK           0060000         /* block special device */
+#define        IFREG           0100000         /* regular file */
+#define        IFLNK           0120000         /* symbolic link */
+#define        IFSOCK          0140000         /* UNIX domain socket */
+
+#define        ISUID           04000           /* set user identifier when exec'ing */
+#define        ISGID           02000           /* set group identifier when exec'ing */
+#define        ISVTX           01000           /* save execution information on exit */
+#define        IREAD           0400            /* read permission */
+#define        IWRITE          0200            /* write permission */
+#define        IEXEC           0100            /* execute permission */
diff --git a/usr/src/sys.386bsd/ufs/dir.h b/usr/src/sys.386bsd/ufs/dir.h
new file mode 100644 (file)
index 0000000..b5c154e
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dir.h       7.10 (Berkeley) 3/25/91
+ */
+
+#ifndef _DIR_H_
+#define        _DIR_H_
+
+/*
+ * A directory consists of some number of blocks of DIRBLKSIZ
+ * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+ * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+ *
+ * Each DIRBLKSIZ byte block contains some number of directory entry
+ * structures, which are of variable length.  Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry.  These are followed by the name padded to a 4 byte boundary
+ * with null bytes.  All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ *
+ * The macro DIRSIZ(dp) gives the amount of space required to represent
+ * a directory entry.  Free space in a directory is represented by
+ * entries which have dp->d_reclen > DIRSIZ(dp).  All DIRBLKSIZ bytes
+ * in a directory block are claimed by the directory entries.  This
+ * usually results in the last entry in a directory having a large
+ * dp->d_reclen.  When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->d_reclen.  If the first entry of
+ * a directory block is free, then its dp->d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->d_ino set to 0.
+ */
+#define DIRBLKSIZ      DEV_BSIZE
+#define        MAXNAMLEN       255
+
+struct direct {
+       u_long  d_ino;                  /* inode number of entry */
+       u_short d_reclen;               /* length of this record */
+       u_short d_namlen;               /* length of string in d_name */
+       char    d_name[MAXNAMLEN + 1];  /* name with length <= MAXNAMLEN */
+};
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry.  This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#define DIRSIZ(dp) \
+    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+
+/*
+ * Template for manipulating directories.
+ * Should use struct direct's, but the name field
+ * is MAXNAMLEN - 1, and this just won't do.
+ */
+struct dirtemplate {
+       u_long  dot_ino;
+       short   dot_reclen;
+       short   dot_namlen;
+       char    dot_name[4];            /* must be multiple of 4 */
+       u_long  dotdot_ino;
+       short   dotdot_reclen;
+       short   dotdot_namlen;
+       char    dotdot_name[4];         /* ditto */
+};
+#endif /* !_DIR_H_ */
diff --git a/usr/src/sys.386bsd/ufs/fs.h b/usr/src/sys.386bsd/ufs/fs.h
new file mode 100644 (file)
index 0000000..37ad2b3
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)fs.h        7.12 (Berkeley) 5/8/91
+ */
+
+/*
+ * Each disk drive contains some number of file systems.
+ * A file system consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A file system is described by its super-block, which in turn
+ * describes the cylinder groups.  The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss.  This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For file system fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ *     [fs->fs_sblkno]         Super-block
+ *     [fs->fs_cblkno]         Cylinder group block
+ *     [fs->fs_iblkno]         Inode blocks
+ *     [fs->fs_dblkno]         Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * The first boot and super blocks are given in absolute disk addresses.
+ * The byte-offset forms are preferred, as they don't imply a sector size.
+ */
+#define BBSIZE         8192
+#define SBSIZE         8192
+#define        BBOFF           ((off_t)(0))
+#define        SBOFF           ((off_t)(BBOFF + BBSIZE))
+#define        BBLOCK          ((daddr_t)(0))
+#define        SBLOCK          ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE))
+
+/*
+ * Addresses stored in inodes are capable of addressing fragments
+ * of `blocks'. File system blocks of at most size MAXBSIZE can 
+ * be optionally broken into 2, 4, or 8 pieces, each of which is
+ * addressible; these pieces may be DEV_BSIZE, or some multiple of
+ * a DEV_BSIZE unit.
+ *
+ * Large files consist of exclusively large data blocks.  To avoid
+ * undue wasted disk space, the last data block of a small file may be
+ * allocated as only as many fragments of a large block as are
+ * necessary.  The file system format retains only a single pointer
+ * to such a fragment, which is a piece of a single large block that
+ * has been divided.  The size of such a fragment is determinable from
+ * information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
+ *
+ * The file system records space availability at the fragment level;
+ * to determine block availability, aligned fragments are examined.
+ *
+ * The root inode is the root of the file system.
+ * Inode 0 can't be used for normal purposes and
+ * historically bad blocks were linked to inode 1,
+ * thus the root inode is 2. (inode 1 is no longer used for
+ * this purpose, however numerous dump tapes make this
+ * assumption, so we are stuck with it)
+ */
+#define        ROOTINO         ((ino_t)2)
+
+/*
+ * MINBSIZE is the smallest allowable block size.
+ * In order to insure that it is possible to create files of size
+ * 2^32 with only two levels of indirection, MINBSIZE is set to 4096.
+ * MINBSIZE must be big enough to hold a cylinder group block,
+ * thus changes to (struct cg) must keep its size within MINBSIZE.
+ * Note that super blocks are always of size SBSIZE,
+ * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE.
+ */
+#define MINBSIZE       4096
+
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in 
+ * the super block for this name.
+ * The limit on the amount of summary information per file system
+ * is defined by MAXCSBUFS. It is currently parameterized for a
+ * maximum of two million cylinders.
+ */
+#define MAXMNTLEN 512
+#define MAXCSBUFS 32
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks.  These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ *
+ * N.B. sizeof(struct csum) must be a power of two in order for
+ * the ``fs_cs'' macro to work (see below).
+ */
+struct csum {
+       long    cs_ndir;        /* number of directories */
+       long    cs_nbfree;      /* number of free blocks */
+       long    cs_nifree;      /* number of free inodes */
+       long    cs_nffree;      /* number of free frags */
+};
+
+/*
+ * Super block for a file system.
+ */
+#define        FS_MAGIC        0x011954
+#define        FSOKAY          0x7c269d38
+struct fs
+{
+       struct  fs *fs_link;            /* linked list of file systems */
+       struct  fs *fs_rlink;           /*     used for incore super blocks */
+       daddr_t fs_sblkno;              /* addr of super-block in filesys */
+       daddr_t fs_cblkno;              /* offset of cyl-block in filesys */
+       daddr_t fs_iblkno;              /* offset of inode-blocks in filesys */
+       daddr_t fs_dblkno;              /* offset of first data after cg */
+       long    fs_cgoffset;            /* cylinder group offset in cylinder */
+       long    fs_cgmask;              /* used to calc mod fs_ntrak */
+       time_t  fs_time;                /* last time written */
+       long    fs_size;                /* number of blocks in fs */
+       long    fs_dsize;               /* number of data blocks in fs */
+       long    fs_ncg;                 /* number of cylinder groups */
+       long    fs_bsize;               /* size of basic blocks in fs */
+       long    fs_fsize;               /* size of frag blocks in fs */
+       long    fs_frag;                /* number of frags in a block in fs */
+/* these are configuration parameters */
+       long    fs_minfree;             /* minimum percentage of free blocks */
+       long    fs_rotdelay;            /* num of ms for optimal next block */
+       long    fs_rps;                 /* disk revolutions per second */
+/* these fields can be computed from the others */
+       long    fs_bmask;               /* ``blkoff'' calc of blk offsets */
+       long    fs_fmask;               /* ``fragoff'' calc of frag offsets */
+       long    fs_bshift;              /* ``lblkno'' calc of logical blkno */
+       long    fs_fshift;              /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+       long    fs_maxcontig;           /* max number of contiguous blks */
+       long    fs_maxbpg;              /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+       long    fs_fragshift;           /* block to frag shift */
+       long    fs_fsbtodb;             /* fsbtodb and dbtofsb shift constant */
+       long    fs_sbsize;              /* actual size of super block */
+       long    fs_csmask;              /* csum block offset */
+       long    fs_csshift;             /* csum block number */
+       long    fs_nindir;              /* value of NINDIR */
+       long    fs_inopb;               /* value of INOPB */
+       long    fs_nspf;                /* value of NSPF */
+/* yet another configuration parameter */
+       long    fs_optim;               /* optimization preference, see below */
+/* these fields are derived from the hardware */
+       long    fs_npsect;              /* # sectors/track including spares */
+       long    fs_interleave;          /* hardware sector interleave */
+       long    fs_trackskew;           /* sector 0 skew, per track */
+       long    fs_headswitch;          /* head switch time, usec */
+       long    fs_trkseek;             /* track-to-track seek, usec */
+/* sizes determined by number of cylinder groups and their sizes */
+       daddr_t fs_csaddr;              /* blk addr of cyl grp summary area */
+       long    fs_cssize;              /* size of cyl grp summary area */
+       long    fs_cgsize;              /* cylinder group size */
+/* these fields are derived from the hardware */
+       long    fs_ntrak;               /* tracks per cylinder */
+       long    fs_nsect;               /* sectors per track */
+       long    fs_spc;                 /* sectors per cylinder */
+/* this comes from the disk driver partitioning */
+       long    fs_ncyl;                /* cylinders in file system */
+/* these fields can be computed from the others */
+       long    fs_cpg;                 /* cylinders per group */
+       long    fs_ipg;                 /* inodes per group */
+       long    fs_fpg;                 /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+       struct  csum fs_cstotal;        /* cylinder summary information */
+/* these fields are cleared at mount time */
+       char    fs_fmod;                /* super block modified flag */
+       char    fs_clean;               /* file system is clean flag */
+       char    fs_ronly;               /* mounted read-only flag */
+       char    fs_flags;               /* currently unused flag */
+       char    fs_fsmnt[MAXMNTLEN];    /* name mounted on */
+/* these fields retain the current block allocation info */
+       long    fs_cgrotor;             /* last cg searched */
+       struct  csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */
+       long    fs_cpc;                 /* cyl per cycle in postbl */
+       short   fs_opostbl[16][8];      /* old rotation block list head */
+       long    fs_sparecon[55];        /* reserved for future constants */
+       long    fs_state;               /* validate fs_clean field */
+       quad    fs_qbmask;              /* ~fs_bmask - for use with quad size */
+       quad    fs_qfmask;              /* ~fs_fmask - for use with quad size */
+       long    fs_postblformat;        /* format of positional layout tables */
+       long    fs_nrpos;               /* number of rotaional positions */
+       long    fs_postbloff;           /* (short) rotation block list head */
+       long    fs_rotbloff;            /* (u_char) blocks for each rotation */
+       long    fs_magic;               /* magic number */
+       u_char  fs_space[1];            /* list of blocks for each rotation */
+/* actually longer */
+};
+/*
+ * Preference for optimization.
+ */
+#define FS_OPTTIME     0       /* minimize allocation time */
+#define FS_OPTSPACE    1       /* minimize disk fragmentation */
+
+/*
+ * Rotational layout table format types
+ */
+#define FS_42POSTBLFMT         -1      /* 4.2BSD rotational table format */
+#define FS_DYNAMICPOSTBLFMT    1       /* dynamic rotational table format */
+/*
+ * Macros for access to superblock array structures
+ */
+#define fs_postbl(fs, cylno) \
+    (((fs)->fs_postblformat == FS_42POSTBLFMT) \
+    ? ((fs)->fs_opostbl[cylno]) \
+    : ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos))
+#define fs_rotbl(fs) \
+    (((fs)->fs_postblformat == FS_42POSTBLFMT) \
+    ? ((fs)->fs_space) \
+    : ((u_char *)((char *)(fs) + (fs)->fs_rotbloff)))
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ *
+ * N.B. This macro assumes that sizeof(struct csum) is a power of two.
+ */
+#define fs_cs(fs, indx) \
+       fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask]
+
+/*
+ * Cylinder group block for a file system.
+ */
+#define        CG_MAGIC        0x090255
+struct cg {
+       struct  cg *cg_link;            /* linked list of cyl groups */
+       long    cg_magic;               /* magic number */
+       time_t  cg_time;                /* time last written */
+       long    cg_cgx;                 /* we are the cgx'th cylinder group */
+       short   cg_ncyl;                /* number of cyl's this cg */
+       short   cg_niblk;               /* number of inode blocks this cg */
+       long    cg_ndblk;               /* number of data blocks this cg */
+       struct  csum cg_cs;             /* cylinder summary information */
+       long    cg_rotor;               /* position of last used block */
+       long    cg_frotor;              /* position of last used frag */
+       long    cg_irotor;              /* position of last used inode */
+       long    cg_frsum[MAXFRAG];      /* counts of available frags */
+       long    cg_btotoff;             /* (long) block totals per cylinder */
+       long    cg_boff;                /* (short) free block positions */
+       long    cg_iusedoff;            /* (char) used inode map */
+       long    cg_freeoff;             /* (u_char) free block map */
+       long    cg_nextfreeoff;         /* (u_char) next available space */
+       long    cg_sparecon[16];        /* reserved for future use */
+       u_char  cg_space[1];            /* space for cylinder group maps */
+/* actually longer */
+};
+/*
+ * Macros for access to cylinder group array structures
+ */
+#define cg_blktot(cgp) \
+    (((cgp)->cg_magic != CG_MAGIC) \
+    ? (((struct ocg *)(cgp))->cg_btot) \
+    : ((long *)((char *)(cgp) + (cgp)->cg_btotoff)))
+#define cg_blks(fs, cgp, cylno) \
+    (((cgp)->cg_magic != CG_MAGIC) \
+    ? (((struct ocg *)(cgp))->cg_b[cylno]) \
+    : ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos))
+#define cg_inosused(cgp) \
+    (((cgp)->cg_magic != CG_MAGIC) \
+    ? (((struct ocg *)(cgp))->cg_iused) \
+    : ((char *)((char *)(cgp) + (cgp)->cg_iusedoff)))
+#define cg_blksfree(cgp) \
+    (((cgp)->cg_magic != CG_MAGIC) \
+    ? (((struct ocg *)(cgp))->cg_free) \
+    : ((u_char *)((char *)(cgp) + (cgp)->cg_freeoff)))
+#define cg_chkmagic(cgp) \
+    ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC)
+
+/*
+ * The following structure is defined
+ * for compatibility with old file systems.
+ */
+struct ocg {
+       struct  ocg *cg_link;           /* linked list of cyl groups */
+       struct  ocg *cg_rlink;          /*     used for incore cyl groups */
+       time_t  cg_time;                /* time last written */
+       long    cg_cgx;                 /* we are the cgx'th cylinder group */
+       short   cg_ncyl;                /* number of cyl's this cg */
+       short   cg_niblk;               /* number of inode blocks this cg */
+       long    cg_ndblk;               /* number of data blocks this cg */
+       struct  csum cg_cs;             /* cylinder summary information */
+       long    cg_rotor;               /* position of last used block */
+       long    cg_frotor;              /* position of last used frag */
+       long    cg_irotor;              /* position of last used inode */
+       long    cg_frsum[8];            /* counts of available frags */
+       long    cg_btot[32];            /* block totals per cylinder */
+       short   cg_b[32][8];            /* positions of free blocks */
+       char    cg_iused[256];          /* used inode map */
+       long    cg_magic;               /* magic number */
+       u_char  cg_free[1];             /* free block map */
+/* actually longer */
+};
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
+#define        dbtofsb(fs, b)  ((b) >> (fs)->fs_fsbtodb)
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define        cgbase(fs, c)   ((daddr_t)((fs)->fs_fpg * (c)))
+#define cgstart(fs, c) \
+       (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask)))
+#define        cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno)      /* super blk */
+#define        cgtod(fs, c)    (cgstart(fs, c) + (fs)->fs_cblkno)      /* cg block */
+#define        cgimin(fs, c)   (cgstart(fs, c) + (fs)->fs_iblkno)      /* inode blk */
+#define        cgdmin(fs, c)   (cgstart(fs, c) + (fs)->fs_dblkno)      /* 1st data */
+
+/*
+ * Macros for handling inode numbers:
+ *     inode number to file system block offset.
+ *     inode number to cylinder group number.
+ *     inode number to file system block address.
+ */
+#define        itoo(fs, x)     ((x) % INOPB(fs))
+#define        itog(fs, x)     ((x) / (fs)->fs_ipg)
+#define        itod(fs, x) \
+       ((daddr_t)(cgimin(fs, itog(fs, x)) + \
+       (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define        dtog(fs, d)     ((d) / (fs)->fs_fpg)
+#define        dtogd(fs, d)    ((d) % (fs)->fs_fpg)
+
+/*
+ * Extract the bits for a block from a map.
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define blkmap(fs, map, loc) \
+    (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag)))
+#define cbtocylno(fs, bno) \
+    ((bno) * NSPF(fs) / (fs)->fs_spc)
+#define cbtorpos(fs, bno) \
+    (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \
+     (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \
+     (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc)                /* calculates (loc % fs->fs_bsize) */ \
+       ((loc) & ~(fs)->fs_bmask)
+#define fragoff(fs, loc)       /* calculates (loc % fs->fs_fsize) */ \
+       ((loc) & ~(fs)->fs_fmask)
+#define lblktosize(fs, blk)    /* calculates (blk * fs->fs_bsize) */ \
+       ((blk) << (fs)->fs_bshift)
+#define lblkno(fs, loc)                /* calculates (loc / fs->fs_bsize) */ \
+       ((loc) >> (fs)->fs_bshift)
+#define numfrags(fs, loc)      /* calculates (loc / fs->fs_fsize) */ \
+       ((loc) >> (fs)->fs_fshift)
+#define blkroundup(fs, size)   /* calculates roundup(size, fs->fs_bsize) */ \
+       (((size) + (fs)->fs_bsize - 1) & (fs)->fs_bmask)
+#define fragroundup(fs, size)  /* calculates roundup(size, fs->fs_fsize) */ \
+       (((size) + (fs)->fs_fsize - 1) & (fs)->fs_fmask)
+#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
+       ((frags) >> (fs)->fs_fragshift)
+#define blkstofrags(fs, blks)  /* calculates (blks * fs->fs_frag) */ \
+       ((blks) << (fs)->fs_fragshift)
+#define fragnum(fs, fsb)       /* calculates (fsb % fs->fs_frag) */ \
+       ((fsb) & ((fs)->fs_frag - 1))
+#define blknum(fs, fsb)                /* calculates rounddown(fsb, fs->fs_frag) */ \
+       ((fsb) &~ ((fs)->fs_frag - 1))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve
+ */
+#define freespace(fs, percentreserved) \
+       (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \
+       (fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100))
+
+/*
+ * Determining the size of a file block in the file system.
+ */
+#define blksize(fs, ip, lbn) \
+       (((lbn) >= NDADDR || (ip)->i_size >= ((lbn) + 1) << (fs)->fs_bshift) \
+           ? (fs)->fs_bsize \
+           : (fragroundup(fs, blkoff(fs, (ip)->i_size))))
+#define dblksize(fs, dip, lbn) \
+       (((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \
+           ? (fs)->fs_bsize \
+           : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
+
+/*
+ * Number of disk sectors per block; assumes DEV_BSIZE byte sector size.
+ */
+#define        NSPB(fs)        ((fs)->fs_nspf << (fs)->fs_fragshift)
+#define        NSPF(fs)        ((fs)->fs_nspf)
+
+/*
+ * INOPB is the number of inodes in a secondary storage block.
+ */
+#define        INOPB(fs)       ((fs)->fs_inopb)
+#define        INOPF(fs)       ((fs)->fs_inopb >> (fs)->fs_fragshift)
+
+/*
+ * NINDIR is the number of indirects in a file system block.
+ */
+#define        NINDIR(fs)      ((fs)->fs_nindir)
diff --git a/usr/src/sys.386bsd/ufs/inode.h b/usr/src/sys.386bsd/ufs/inode.h
new file mode 100644 (file)
index 0000000..b945ae4
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1982, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)inode.h     7.17 (Berkeley) 5/8/91
+ */
+
+#ifdef KERNEL
+#include "../ufs/dinode.h"
+#else
+#include <ufs/dinode.h>
+#endif
+
+/*
+ * The inode is used to describe each active (or recently active)
+ * file in the UFS filesystem. It is composed of two types of
+ * information. The first part is the information that is needed
+ * only while the file is active (such as the identity of the file
+ * and linkage to speed its lookup). The second part is the 
+ * permannent meta-data associated with the file which is read
+ * in from the permanent dinode from long term storage when the
+ * file becomes active, and is put back when the file is no longer
+ * being used.
+ */
+struct inode {
+       struct  inode *i_chain[2]; /* hash chain, MUST be first */
+       struct  vnode *i_vnode; /* vnode associated with this inode */
+       struct  vnode *i_devvp; /* vnode for block I/O */
+       u_long  i_flag;         /* see below */
+       dev_t   i_dev;          /* device where inode resides */
+       ino_t   i_number;       /* the identity of the inode */
+       struct  fs *i_fs;       /* filesystem associated with this inode */
+       struct  dquot *i_dquot[MAXQUOTAS]; /* pointer to dquot structures */
+       struct  lockf *i_lockf; /* head of byte-level lock list */
+       long    i_diroff;       /* offset in dir, where we found last entry */
+       off_t   i_endoff;       /* end of useful stuff in directory */
+       long    i_spare0;
+       long    i_spare1;
+       struct  dinode i_din;   /* the on-disk dinode */
+};
+
+#define        i_mode          i_din.di_mode
+#define        i_nlink         i_din.di_nlink
+#define        i_uid           i_din.di_uid
+#define        i_gid           i_din.di_gid
+#if BYTE_ORDER == LITTLE_ENDIAN || defined(tahoe) /* ugh! -- must be fixed */
+#define        i_size          i_din.di_qsize.val[0]
+#else /* BYTE_ORDER == BIG_ENDIAN */
+#define        i_size          i_din.di_qsize.val[1]
+#endif
+#define        i_db            i_din.di_db
+#define        i_ib            i_din.di_ib
+#define        i_atime         i_din.di_atime
+#define        i_mtime         i_din.di_mtime
+#define        i_ctime         i_din.di_ctime
+#define i_blocks       i_din.di_blocks
+#define        i_rdev          i_din.di_db[0]
+#define i_flags                i_din.di_flags
+#define i_gen          i_din.di_gen
+#define        i_forw          i_chain[0]
+#define        i_back          i_chain[1]
+
+/* flags */
+#define        ILOCKED         0x0001          /* inode is locked */
+#define        IWANT           0x0002          /* some process waiting on lock */
+#define        IRENAME         0x0004          /* inode is being renamed */
+#define        IUPD            0x0010          /* file has been modified */
+#define        IACC            0x0020          /* inode access time to be updated */
+#define        ICHG            0x0040          /* inode has been changed */
+#define        IMOD            0x0080          /* inode has been modified */
+#define        ISHLOCK         0x0100          /* file has shared lock */
+#define        IEXLOCK         0x0200          /* file has exclusive lock */
+#define        ILWAIT          0x0400          /* someone waiting on file lock */
+
+#ifdef KERNEL
+/*
+ * Convert between inode pointers and vnode pointers
+ */
+#define VTOI(vp)       ((struct inode *)(vp)->v_data)
+#define ITOV(ip)       ((ip)->i_vnode)
+
+/*
+ * Convert between vnode types and inode formats
+ */
+extern enum vtype      iftovt_tab[];
+extern int             vttoif_tab[];
+#define IFTOVT(mode)   (iftovt_tab[((mode) & IFMT) >> 12])
+#define VTTOIF(indx)   (vttoif_tab[(int)(indx)])
+
+#define MAKEIMODE(indx, mode)  (int)(VTTOIF(indx) | (mode))
+
+u_long nextgennumber;          /* next generation number to assign */
+
+extern ino_t   dirpref();
+
+/*
+ * Lock and unlock inodes.
+ */
+#ifdef notdef
+#define        ILOCK(ip) { \
+       while ((ip)->i_flag & ILOCKED) { \
+               (ip)->i_flag |= IWANT; \
+               (void) sleep((caddr_t)(ip), PINOD); \
+       } \
+       (ip)->i_flag |= ILOCKED; \
+}
+
+#define        IUNLOCK(ip) { \
+       (ip)->i_flag &= ~ILOCKED; \
+       if ((ip)->i_flag&IWANT) { \
+               (ip)->i_flag &= ~IWANT; \
+               wakeup((caddr_t)(ip)); \
+       } \
+}
+#else
+#define ILOCK(ip)      ilock(ip)
+#define IUNLOCK(ip)    iunlock(ip)
+#endif
+
+#define        IUPDAT(ip, t1, t2, waitfor) { \
+       if (ip->i_flag&(IUPD|IACC|ICHG|IMOD)) \
+               (void) iupdat(ip, t1, t2, waitfor); \
+}
+
+#define        ITIMES(ip, t1, t2) { \
+       if ((ip)->i_flag&(IUPD|IACC|ICHG)) { \
+               (ip)->i_flag |= IMOD; \
+               if ((ip)->i_flag&IACC) \
+                       (ip)->i_atime = (t1)->tv_sec; \
+               if ((ip)->i_flag&IUPD) \
+                       (ip)->i_mtime = (t2)->tv_sec; \
+               if ((ip)->i_flag&ICHG) \
+                       (ip)->i_ctime = time.tv_sec; \
+               (ip)->i_flag &= ~(IACC|IUPD|ICHG); \
+       } \
+}
+
+/*
+ * This overlays the fid sturcture (see mount.h)
+ */
+struct ufid {
+       u_short ufid_len;       /* length of structure */
+       u_short ufid_pad;       /* force long alignment */
+       ino_t   ufid_ino;       /* file number (ino) */
+       long    ufid_gen;       /* generation number */
+};
+
+/*
+ * Prototypes for UFS vnode operations
+ */
+int ufs_lookup __P((struct vnode *vp, struct nameidata *ndp, struct proc *p));
+int ufs_create __P((struct nameidata *ndp, struct vattr *vap, struct proc *p));
+int ufs_mknod __P((struct nameidata *ndp, struct vattr *vap, struct ucred *cred,
+       struct proc *p));
+int ufs_open __P((struct vnode *vp, int mode, struct ucred *cred,
+       struct proc *p));
+int ufs_close __P((struct vnode *vp, int fflag, struct ucred *cred,
+       struct proc *p));
+int ufs_access __P((struct vnode *vp, int mode, struct ucred *cred,
+       struct proc *p));
+int ufs_getattr __P((struct vnode *vp, struct vattr *vap, struct ucred *cred,
+       struct proc *p));
+int ufs_setattr __P((struct vnode *vp, struct vattr *vap, struct ucred *cred,
+       struct proc *p));
+int ufs_read __P((struct vnode *vp, struct uio *uio, int ioflag,
+       struct ucred *cred));
+int ufs_write __P((struct vnode *vp, struct uio *uio, int ioflag,
+       struct ucred *cred));
+int ufs_ioctl __P((struct vnode *vp, int command, caddr_t data, int fflag,
+       struct ucred *cred, struct proc *p));
+int ufs_select __P((struct vnode *vp, int which, int fflags, struct ucred *cred,
+       struct proc *p));
+int ufs_mmap __P((struct vnode *vp, int fflags, struct ucred *cred,
+       struct proc *p));
+int ufs_fsync __P((struct vnode *vp, int fflags, struct ucred *cred,
+       int waitfor, struct proc *p));
+int ufs_seek __P((struct vnode *vp, off_t oldoff, off_t newoff,
+       struct ucred *cred));
+int ufs_remove __P((struct nameidata *ndp, struct proc *p));
+int ufs_link __P((struct vnode *vp, struct nameidata *ndp, struct proc *p));
+int ufs_rename __P((struct nameidata *fndp, struct nameidata *tdnp,
+       struct proc *p));
+int ufs_mkdir __P((struct nameidata *ndp, struct vattr *vap, struct proc *p));
+int ufs_rmdir __P((struct nameidata *ndp, struct proc *p));
+int ufs_symlink __P((struct nameidata *ndp, struct vattr *vap, char *target,
+       struct proc *p));
+int ufs_readdir __P((struct vnode *vp, struct uio *uio, struct ucred *cred,
+       int *eofflagp));
+int ufs_readlink __P((struct vnode *vp, struct uio *uio, struct ucred *cred));
+int ufs_abortop __P((struct nameidata *ndp));
+int ufs_inactive __P((struct vnode *vp, struct proc *p));
+int ufs_reclaim __P((struct vnode *vp));
+int ufs_lock __P((struct vnode *vp));
+int ufs_unlock __P((struct vnode *vp));
+int ufs_bmap __P((struct vnode *vp, daddr_t bn, struct vnode **vpp,
+       daddr_t *bnp));
+int ufs_strategy __P((struct buf *bp));
+int ufs_print __P((struct vnode *vp));
+int ufs_islocked __P((struct vnode *vp));
+int ufs_advlock __P((struct vnode *vp, caddr_t id, int op, struct flock *fl,
+       int flags));
+#endif /* KERNEL */
diff --git a/usr/src/sys.386bsd/ufs/lockf.h b/usr/src/sys.386bsd/ufs/lockf.h
new file mode 100644 (file)
index 0000000..5ac4c6a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Scooter Morris at Genentech Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)lockf.h     7.1 (Berkeley) 2/1/91
+ */
+
+/*
+ * The lockf structure is a kernel structure which contains all the
+ * information associated with a byte range lock. The lockf structures
+ * are linked into the inode structure. Locks are sorted by the starting
+ * byte of the lock for efficiency.
+ */
+struct lockf {
+       short   lf_flags;        /* Lock semantics: F_POSIX, F_FLOCK, F_WAIT */
+       short   lf_type;         /* Lock type: F_RDLCK, F_WRLCK */
+       off_t   lf_start;        /* The byte # of the start of the lock */
+       off_t   lf_end;          /* The byte # of the end of the lock (-1=EOF)*/
+       caddr_t lf_id;           /* The id of the resource holding the lock */
+       struct  inode *lf_inode; /* Back pointer to the inode */
+       struct  lockf *lf_next;  /* A pointer to the next lock on this inode */
+       struct  lockf *lf_block; /* The list of blocked locks */
+};
+
+/*
+ * Maximum length of sleep chains to traverse to try and detect deadlock.
+ */
+#define MAXDEPTH 50
+
+#ifdef KERNEL
+/*
+ * Public lock manipulation routines
+ */
+extern struct lockf *lf_remove();      /* Remove a lock */
+extern struct lockf *lf_getblock();    /* Return the first blocking lock */
+
+#ifdef LOCKF_DEBUG
+extern int lockf_debug;
+#endif LOCKF_DEBUG
+#endif KERNEL
diff --git a/usr/src/sys.386bsd/ufs/mfs_vfsops.c b/usr/src/sys.386bsd/ufs/mfs_vfsops.c
new file mode 100644 (file)
index 0000000..d2085f1
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1989, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mfs_vfsops.c        7.19 (Berkeley) 4/16/91
+ */
+
+#include "param.h"
+#include "time.h"
+#include "kernel.h"
+#include "proc.h"
+#include "buf.h"
+#include "mount.h"
+#include "signalvar.h"
+#include "vnode.h"
+
+#include "quota.h"
+#include "inode.h"
+#include "ufsmount.h"
+#include "mfsnode.h"
+#include "fs.h"
+
+extern struct vnodeops mfs_vnodeops;
+
+/*
+ * mfs vfs operations.
+ */
+int mfs_mount();
+int mfs_start();
+int ufs_unmount();
+int ufs_root();
+int ufs_quotactl();
+int mfs_statfs();
+int ufs_sync();
+int ufs_fhtovp();
+int ufs_vptofh();
+int mfs_init();
+
+struct vfsops mfs_vfsops = {
+       mfs_mount,
+       mfs_start,
+       ufs_unmount,
+       ufs_root,
+       ufs_quotactl,
+       mfs_statfs,
+       ufs_sync,
+       ufs_fhtovp,
+       ufs_vptofh,
+       mfs_init,
+};
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ */
+/* ARGSUSED */
+mfs_mount(mp, path, data, ndp, p)
+       register struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+       struct proc *p;
+{
+       struct vnode *devvp;
+       struct mfs_args args;
+       struct ufsmount *ump;
+       register struct fs *fs;
+       register struct mfsnode *mfsp;
+       static int mfs_minor;
+       u_int size;
+       int error;
+
+       if (mp->mnt_flag & MNT_UPDATE) {
+               ump = VFSTOUFS(mp);
+               fs = ump->um_fs;
+               if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
+                       fs->fs_ronly = 0;
+               return (0);
+       }
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct mfs_args)))
+               return (error);
+       error = getnewvnode(VT_MFS, (struct mount *)0, &mfs_vnodeops, &devvp);
+       if (error)
+               return (error);
+       devvp->v_type = VBLK;
+       if (checkalias(devvp, makedev(255, mfs_minor++), (struct mount *)0))
+               panic("mfs_mount: dup dev");
+       mfsp = VTOMFS(devvp);
+       mfsp->mfs_baseoff = args.base;
+       mfsp->mfs_size = args.size;
+       mfsp->mfs_vnode = devvp;
+       mfsp->mfs_pid = p->p_pid;
+       mfsp->mfs_buflist = (struct buf *)0;
+       if (error = mountfs(devvp, mp)) {
+               mfsp->mfs_buflist = (struct buf *)-1;
+               vrele(devvp);
+               return (error);
+       }
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
+       bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
+       bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
+               MNAMELEN);
+       (void) copyinstr(args.name, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+               &size);
+       bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+       (void) mfs_statfs(mp, &mp->mnt_stat);
+       return (0);
+}
+
+int    mfs_pri = PWAIT | PCATCH;               /* XXX prob. temp */
+
+/*
+ * Used to grab the process and keep it in the kernel to service
+ * memory filesystem I/O requests.
+ *
+ * Loop servicing I/O requests.
+ * Copy the requested data into or out of the memory filesystem
+ * address space.
+ */
+/* ARGSUSED */
+mfs_start(mp, flags, p)
+       struct mount *mp;
+       int flags;
+       struct proc *p;
+{
+       register struct vnode *vp = VFSTOUFS(mp)->um_devvp;
+       register struct mfsnode *mfsp = VTOMFS(vp);
+       register struct buf *bp;
+       register caddr_t base;
+       int error = 0;
+
+       base = mfsp->mfs_baseoff;
+       while (mfsp->mfs_buflist != (struct buf *)(-1)) {
+               while (bp = mfsp->mfs_buflist) {
+                       mfsp->mfs_buflist = bp->av_forw;
+                       mfs_doio(bp, base);
+                       wakeup((caddr_t)bp);
+               }
+               /*
+                * If a non-ignored signal is received, try to unmount.
+                * If that fails, clear the signal (it has been "processed"),
+                * otherwise we will loop here, as tsleep will always return
+                * EINTR/ERESTART.
+                */
+               if (error = tsleep((caddr_t)vp, mfs_pri, "mfsidl", 0))
+                       if (dounmount(mp, MNT_NOFORCE, p) != 0)
+                               CLRSIG(p, CURSIG(p));
+       }
+       return (error);
+}
+
+/*
+ * Get file system statistics.
+ */
+mfs_statfs(mp, sbp, p)
+       struct mount *mp;
+       struct statfs *sbp;
+       struct proc *p;
+{
+       int error;
+
+       error = ufs_statfs(mp, sbp, p);
+       sbp->f_type = MOUNT_MFS;
+       return (error);
+}
diff --git a/usr/src/sys.386bsd/ufs/mfsiom.h b/usr/src/sys.386bsd/ufs/mfsiom.h
new file mode 100644 (file)
index 0000000..855a86b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mfsiom.h    7.2 (Berkeley) 6/28/90
+ */
+
+#define MFS_MAPREG     (MAXPHYS/NBPG + 2) /* Kernel mapping pte's */
+#define MFS_MAPSIZE    10                 /* Size of alloc map for pte's */
diff --git a/usr/src/sys.386bsd/ufs/mfsnode.h b/usr/src/sys.386bsd/ufs/mfsnode.h
new file mode 100644 (file)
index 0000000..2673591
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)mfsnode.h   7.3 (Berkeley) 4/16/91
+ */
+
+/*
+ * This structure defines the control data for the memory
+ * based file system.
+ */
+
+struct mfsnode {
+       struct  vnode *mfs_vnode;       /* vnode associated with this mfsnode */
+       caddr_t mfs_baseoff;            /* base of file system in memory */
+       long    mfs_size;               /* size of memory file system */
+       pid_t   mfs_pid;                /* supporting process pid */
+       struct  buf *mfs_buflist;       /* list of I/O requests */
+       long    mfs_spare[4];
+};
+
+/*
+ * Convert between mfsnode pointers and vnode pointers
+ */
+#define VTOMFS(vp)     ((struct mfsnode *)(vp)->v_data)
+#define MFSTOV(mfsp)   ((mfsp)->mfs_vnode)
+
+/*
+ * Prototypes for MFS operations on vnodes.
+ */
+int    mfs_badop();
+#define mfs_lookup ((int (*) __P(( \
+               struct vnode *vp, \
+               struct nameidata *ndp, \
+               struct proc *p))) mfs_badop)
+#define mfs_create ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) mfs_badop)
+#define mfs_mknod ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) mfs_badop)
+int    mfs_open __P((
+               struct vnode *vp,
+               int mode,
+               struct ucred *cred,
+               struct proc *p));
+int    mfs_close __P((
+               struct vnode *vp,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+#define mfs_access ((int (*) __P(( \
+               struct vnode *vp, \
+               int mode, \
+               struct ucred *cred, \
+               struct proc *p))) mfs_badop)
+#define mfs_getattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) mfs_badop)
+#define mfs_setattr ((int (*) __P(( \
+               struct vnode *vp, \
+               struct vattr *vap, \
+               struct ucred *cred, \
+               struct proc *p))) mfs_badop)
+#define mfs_read ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               int ioflag, \
+               struct ucred *cred))) mfs_badop)
+#define mfs_write ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               int ioflag, \
+               struct ucred *cred))) mfs_badop)
+int    mfs_ioctl __P((
+               struct vnode *vp,
+               int command,
+               caddr_t data,
+               int fflag,
+               struct ucred *cred,
+               struct proc *p));
+#define mfs_select ((int (*) __P(( \
+               struct vnode *vp, \
+               int which, \
+               int fflags, \
+               struct ucred *cred, \
+               struct proc *p))) mfs_badop)
+#define mfs_mmap ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               struct proc *p))) mfs_badop)
+#define mfs_fsync ((int (*) __P(( \
+               struct vnode *vp, \
+               int fflags, \
+               struct ucred *cred, \
+               int waitfor, \
+               struct proc *p))) mfs_badop)
+#define mfs_seek ((int (*) __P(( \
+               struct vnode *vp, \
+               off_t oldoff, \
+               off_t newoff, \
+               struct ucred *cred))) mfs_badop)
+#define mfs_remove ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) mfs_badop)
+#define mfs_link ((int (*) __P(( \
+               struct vnode *vp, \
+               struct nameidata *ndp, \
+               struct proc *p))) mfs_badop)
+#define mfs_rename ((int (*) __P(( \
+               struct nameidata *fndp, \
+               struct nameidata *tdnp, \
+               struct proc *p))) mfs_badop)
+#define mfs_mkdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               struct proc *p))) mfs_badop)
+#define mfs_rmdir ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct proc *p))) mfs_badop)
+#define mfs_symlink ((int (*) __P(( \
+               struct nameidata *ndp, \
+               struct vattr *vap, \
+               char *target, \
+               struct proc *p))) mfs_badop)
+#define mfs_readdir ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred, \
+               int *eofflagp))) mfs_badop)
+#define mfs_readlink ((int (*) __P(( \
+               struct vnode *vp, \
+               struct uio *uio, \
+               struct ucred *cred))) mfs_badop)
+#define mfs_abortop ((int (*) __P(( \
+               struct nameidata *ndp))) mfs_badop)
+int    mfs_inactive __P((
+               struct vnode *vp,
+               struct proc *p));
+#define mfs_reclaim ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+#define mfs_lock ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+#define mfs_unlock ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+int    mfs_bmap __P((
+               struct vnode *vp,
+               daddr_t bn,
+               struct vnode **vpp,
+               daddr_t *bnp));
+int    mfs_strategy __P((
+               struct buf *bp));
+int    mfs_print __P((
+               struct vnode *vp));
+#define mfs_islocked ((int (*) __P(( \
+               struct vnode *vp))) nullop)
+#define mfs_advlock ((int (*) __P(( \
+               struct vnode *vp, \
+               caddr_t id, \
+               int op, \
+               struct flock *fl, \
+               int flags))) mfs_badop)
diff --git a/usr/src/sys.386bsd/ufs/quota.h b/usr/src/sys.386bsd/ufs/quota.h
new file mode 100644 (file)
index 0000000..a049e62
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)quota.h     7.9 (Berkeley) 2/22/91
+ */
+
+#ifndef _QUOTA_
+#define _QUOTA_
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits UNIX).
+ *
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define        MAX_IQ_TIME     (7*24*60*60)    /* 1 week */
+#define        MAX_DQ_TIME     (7*24*60*60)    /* 1 week */
+
+/*
+ * The following constants define the usage of the quota file array
+ * in the ufsmount structure and dquot array in the inode structure.
+ * The semantics of the elements of these arrays are defined in the
+ * routine getinoquota; the remainder of the quota code treats them
+ * generically and need not be inspected when changing the size of
+ * the array.
+ */
+#define        MAXQUOTAS       2
+#define        USRQUOTA        0       /* element used for user quotas */
+#define        GRPQUOTA        1       /* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+       "user",         /* USRQUOTA */ \
+       "group",        /* GRPQUOTA */ \
+       "undefined", \
+};
+#define QUOTAFILENAME "quota"
+#define QUOTAGROUP "operator"
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK     0x00ff
+#define SUBCMDSHIFT    8
+#define        QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define        Q_QUOTAON       0x0100  /* enable quotas */
+#define        Q_QUOTAOFF      0x0200  /* disable quotas */
+#define        Q_GETQUOTA      0x0300  /* get limits and usage */
+#define        Q_SETQUOTA      0x0400  /* set limits and usage */
+#define        Q_SETUSE        0x0500  /* set usage */
+#define        Q_SYNC          0x0600  /* sync disk copy of a filesystems quotas */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.  The setquota system call establishes
+ * the vnode for each quota file (a pointer is retained in the ufsmount
+ * structure).
+ */
+struct dqblk {
+       u_long  dqb_bhardlimit; /* absolute limit on disk blks alloc */
+       u_long  dqb_bsoftlimit; /* preferred limit on disk blks */
+       u_long  dqb_curblocks;  /* current block count */
+       u_long  dqb_ihardlimit; /* maximum # allocated inodes + 1 */
+       u_long  dqb_isoftlimit; /* preferred inode limit */
+       u_long  dqb_curinodes;  /* current # allocated inodes */
+       time_t  dqb_btime;      /* time limit for excessive disk use */
+       time_t  dqb_itime;      /* time limit for excessive files */
+};
+
+#ifdef KERNEL
+/*
+ * The following structure records disk usage for a user or group on a
+ * filesystem. There is one allocated for each quota that exists on any
+ * filesystem for the current user or group. A cache is kept of recently
+ * used entries.
+ */
+struct dquot {
+       struct  dquot *dq_forw, *dq_back;/* MUST be first entry */
+       struct  dquot *dq_freef, **dq_freeb; /* free list */
+       short   dq_flags;               /* flags, see below */
+       short   dq_cnt;                 /* count of active references */
+       short   dq_spare;               /* unused spare padding */
+       short   dq_type;                /* quota type of this dquot */
+       u_long  dq_id;                  /* identifier this applies to */
+       struct  ufsmount *dq_ump;       /* filesystem that this is taken from */
+       struct  dqblk dq_dqb;           /* actual usage & quotas */
+};
+/*
+ * Flag values.
+ */
+#define        DQ_LOCK         0x01            /* this quota locked (no MODS) */
+#define        DQ_WANT         0x02            /* wakeup on unlock */
+#define        DQ_MOD          0x04            /* this quota modified since read */
+#define        DQ_FAKE         0x08            /* no limits here, just usage */
+#define        DQ_BLKS         0x10            /* has been warned about blk limit */
+#define        DQ_INODS        0x20            /* has been warned about inode limit */
+/*
+ * Shorthand notation.
+ */
+#define        dq_bhardlimit   dq_dqb.dqb_bhardlimit
+#define        dq_bsoftlimit   dq_dqb.dqb_bsoftlimit
+#define        dq_curblocks    dq_dqb.dqb_curblocks
+#define        dq_ihardlimit   dq_dqb.dqb_ihardlimit
+#define        dq_isoftlimit   dq_dqb.dqb_isoftlimit
+#define        dq_curinodes    dq_dqb.dqb_curinodes
+#define        dq_btime        dq_dqb.dqb_btime
+#define        dq_itime        dq_dqb.dqb_itime
+
+/*
+ * If the system has never checked for a quota for this file,
+ * then it is set to NODQUOT. Once a write attempt is made
+ * the inode pointer is set to reference a dquot structure.
+ */
+#define        NODQUOT         ((struct dquot *) 0)
+
+/*
+ * Flags to chkdq() and chkiq()
+ */
+#define        FORCE   0x01    /* force usage changes independent of limits */
+#define        CHOWN   0x02    /* (advisory) change initiated by chown */
+
+/*
+ * Macros to avoid subroutine calls to trivial functions.
+ */
+#ifndef DIAGNOSTIC
+#define        DQREF(dq)       (dq)->dq_cnt++
+#else
+#define        DQREF(dq)       dqref(dq)
+#endif /* DIAGNOSTIC */
+
+#else
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int    quotactl __P((const char *, int, int, void *));
+__END_DECLS
+
+#endif /* KERNEL */
+#endif /* _QUOTA_ */
diff --git a/usr/src/sys.386bsd/ufs/ufs_alloc.c b/usr/src/sys.386bsd/ufs/ufs_alloc.c
new file mode 100644 (file)
index 0000000..d40445c
--- /dev/null
@@ -0,0 +1,1101 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_alloc.c 7.26 (Berkeley) 5/2/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "proc.h"
+#include "vnode.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "quota.h"
+#include "inode.h"
+#include "fs.h"
+
+extern u_long          hashalloc();
+extern ino_t           ialloccg();
+extern daddr_t         alloccg();
+extern daddr_t         alloccgblk();
+extern daddr_t         fragextend();
+extern daddr_t         blkpref();
+extern daddr_t         mapsearch();
+extern int             inside[], around[];
+extern unsigned char   *fragtbl[];
+
+/*
+ * Allocate a block in the file system.
+ * 
+ * The size of the requested block is given, which must be some
+ * multiple of fs_fsize and <= fs_bsize.
+ * A preference may be optionally specified. If a preference is given
+ * the following hierarchy is used to allocate a block:
+ *   1) allocate the requested block.
+ *   2) allocate a rotationally optimal block in the same cylinder.
+ *   3) allocate a block in the same cylinder group.
+ *   4) quadradically rehash into other cylinder groups, until an
+ *      available block is located.
+ * If no block preference is given the following heirarchy is used
+ * to allocate a block:
+ *   1) allocate a block in the cylinder group that contains the
+ *      inode for the file.
+ *   2) quadradically rehash into other cylinder groups, until an
+ *      available block is located.
+ */
+alloc(ip, lbn, bpref, size, bnp)
+       register struct inode *ip;
+       daddr_t lbn, bpref;
+       int size;
+       daddr_t *bnp;
+{
+       daddr_t bno;
+       register struct fs *fs;
+       register struct buf *bp;
+       int cg, error;
+       struct ucred *cred = curproc->p_ucred;          /* XXX */
+       
+       *bnp = 0;
+       fs = ip->i_fs;
+       if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
+               printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
+                   ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
+               panic("alloc: bad size");
+       }
+       if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
+               goto nospace;
+       if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
+               goto nospace;
+#ifdef QUOTA
+       if (error = chkdq(ip, (long)btodb(size), cred, 0))
+               return (error);
+#endif
+       if (bpref >= fs->fs_size)
+               bpref = 0;
+       if (bpref == 0)
+               cg = itog(fs, ip->i_number);
+       else
+               cg = dtog(fs, bpref);
+       bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size,
+               (u_long (*)())alloccg);
+       if (bno > 0) {
+               ip->i_blocks += btodb(size);
+               ip->i_flag |= IUPD|ICHG;
+               *bnp = bno;
+               return (0);
+       }
+#ifdef QUOTA
+       /*
+        * Restore user's disk quota because allocation failed.
+        */
+       (void) chkdq(ip, (long)-btodb(size), cred, FORCE);
+#endif
+nospace:
+       fserr(fs, cred->cr_uid, "file system full");
+       uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
+       return (ENOSPC);
+}
+
+/*
+ * Reallocate a fragment to a bigger size
+ *
+ * The number and size of the old block is given, and a preference
+ * and new size is also specified. The allocator attempts to extend
+ * the original block. Failing that, the regular block allocator is
+ * invoked to get an appropriate block.
+ */
+realloccg(ip, lbprev, bpref, osize, nsize, bpp)
+       register struct inode *ip;
+       off_t lbprev;
+       daddr_t bpref;
+       int osize, nsize;
+       struct buf **bpp;
+{
+       register struct fs *fs;
+       struct buf *bp, *obp;
+       int cg, request, error;
+       daddr_t bprev, bno;
+       struct ucred *cred = curproc->p_ucred;          /* XXX */
+       
+       *bpp = 0;
+       fs = ip->i_fs;
+       if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
+           (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
+               printf("dev = 0x%x, bsize = %d, osize = %d, nsize = %d, fs = %s\n",
+                   ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt);
+               panic("realloccg: bad size");
+       }
+       if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
+               goto nospace;
+       if ((bprev = ip->i_db[lbprev]) == 0) {
+               printf("dev = 0x%x, bsize = %d, bprev = %d, fs = %s\n",
+                   ip->i_dev, fs->fs_bsize, bprev, fs->fs_fsmnt);
+               panic("realloccg: bad bprev");
+       }
+       /*
+        * Allocate the extra space in the buffer.
+        */
+       if (error = bread(ITOV(ip), lbprev, osize, NOCRED, &bp)) {
+               brelse(bp);
+               return (error);
+       }
+#ifdef QUOTA
+       if (error = chkdq(ip, (long)btodb(nsize - osize), cred, 0)) {
+               brelse(bp);
+               return (error);
+       }
+#endif
+       /*
+        * Check for extension in the existing location.
+        */
+       cg = dtog(fs, bprev);
+       if (bno = fragextend(ip, cg, (long)bprev, osize, nsize)) {
+               if (bp->b_blkno != fsbtodb(fs, bno))
+                       panic("bad blockno");
+               ip->i_blocks += btodb(nsize - osize);
+               ip->i_flag |= IUPD|ICHG;
+               allocbuf(bp, nsize);
+               bp->b_flags |= B_DONE;
+               bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
+               *bpp = bp;
+               return (0);
+       }
+       /*
+        * Allocate a new disk location.
+        */
+       if (bpref >= fs->fs_size)
+               bpref = 0;
+       switch ((int)fs->fs_optim) {
+       case FS_OPTSPACE:
+               /*
+                * Allocate an exact sized fragment. Although this makes 
+                * best use of space, we will waste time relocating it if 
+                * the file continues to grow. If the fragmentation is
+                * less than half of the minimum free reserve, we choose
+                * to begin optimizing for time.
+                */
+               request = nsize;
+               if (fs->fs_minfree < 5 ||
+                   fs->fs_cstotal.cs_nffree >
+                   fs->fs_dsize * fs->fs_minfree / (2 * 100))
+                       break;
+               log(LOG_NOTICE, "%s: optimization changed from SPACE to TIME\n",
+                       fs->fs_fsmnt);
+               fs->fs_optim = FS_OPTTIME;
+               break;
+       case FS_OPTTIME:
+               /*
+                * At this point we have discovered a file that is trying
+                * to grow a small fragment to a larger fragment. To save
+                * time, we allocate a full sized block, then free the 
+                * unused portion. If the file continues to grow, the 
+                * `fragextend' call above will be able to grow it in place
+                * without further copying. If aberrant programs cause
+                * disk fragmentation to grow within 2% of the free reserve,
+                * we choose to begin optimizing for space.
+                */
+               request = fs->fs_bsize;
+               if (fs->fs_cstotal.cs_nffree <
+                   fs->fs_dsize * (fs->fs_minfree - 2) / 100)
+                       break;
+               log(LOG_NOTICE, "%s: optimization changed from TIME to SPACE\n",
+                       fs->fs_fsmnt);
+               fs->fs_optim = FS_OPTSPACE;
+               break;
+       default:
+               printf("dev = 0x%x, optim = %d, fs = %s\n",
+                   ip->i_dev, fs->fs_optim, fs->fs_fsmnt);
+               panic("realloccg: bad optim");
+               /* NOTREACHED */
+       }
+       bno = (daddr_t)hashalloc(ip, cg, (long)bpref, request,
+               (u_long (*)())alloccg);
+       if (bno > 0) {
+               bp->b_blkno = fsbtodb(fs, bno);
+               (void) vnode_pager_uncache(ITOV(ip));
+               blkfree(ip, bprev, (off_t)osize);
+               if (nsize < request)
+                       blkfree(ip, bno + numfrags(fs, nsize),
+                               (off_t)(request - nsize));
+               ip->i_blocks += btodb(nsize - osize);
+               ip->i_flag |= IUPD|ICHG;
+               allocbuf(bp, nsize);
+               bp->b_flags |= B_DONE;
+               bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
+               *bpp = bp;
+               return (0);
+       }
+#ifdef QUOTA
+       /*
+        * Restore user's disk quota because allocation failed.
+        */
+       (void) chkdq(ip, (long)-btodb(nsize - osize), cred, FORCE);
+#endif
+       brelse(bp);
+nospace:
+       /*
+        * no space available
+        */
+       fserr(fs, cred->cr_uid, "file system full");
+       uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
+       return (ENOSPC);
+}
+
+/*
+ * Allocate an inode in the file system.
+ * 
+ * A preference may be optionally specified. If a preference is given
+ * the following hierarchy is used to allocate an inode:
+ *   1) allocate the requested inode.
+ *   2) allocate an inode in the same cylinder group.
+ *   3) quadradically rehash into other cylinder groups, until an
+ *      available inode is located.
+ * If no inode preference is given the following heirarchy is used
+ * to allocate an inode:
+ *   1) allocate an inode in cylinder group 0.
+ *   2) quadradically rehash into other cylinder groups, until an
+ *      available inode is located.
+ */
+ialloc(pip, ipref, mode, cred, ipp)
+       register struct inode *pip;
+       ino_t ipref;
+       int mode;
+       struct ucred *cred;
+       struct inode **ipp;
+{
+       ino_t ino;
+       register struct fs *fs;
+       register struct inode *ip;
+       int cg, error;
+       
+       *ipp = 0;
+       fs = pip->i_fs;
+       if (fs->fs_cstotal.cs_nifree == 0)
+               goto noinodes;
+       if (ipref >= fs->fs_ncg * fs->fs_ipg)
+               ipref = 0;
+       cg = itog(fs, ipref);
+       ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg);
+       if (ino == 0)
+               goto noinodes;
+       error = iget(pip, ino, ipp);
+       if (error) {
+               ifree(pip, ino, mode);
+               return (error);
+       }
+       ip = *ipp;
+       if (ip->i_mode) {
+               printf("mode = 0%o, inum = %d, fs = %s\n",
+                   ip->i_mode, ip->i_number, fs->fs_fsmnt);
+               panic("ialloc: dup alloc");
+       }
+       if (ip->i_blocks) {                             /* XXX */
+               printf("free inode %s/%d had %d blocks\n",
+                   fs->fs_fsmnt, ino, ip->i_blocks);
+               ip->i_blocks = 0;
+       }
+       ip->i_flags = 0;
+       /*
+        * Set up a new generation number for this inode.
+        */
+       if (++nextgennumber < (u_long)time.tv_sec)
+               nextgennumber = time.tv_sec;
+       ip->i_gen = nextgennumber;
+       return (0);
+noinodes:
+       fserr(fs, cred->cr_uid, "out of inodes");
+       uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
+       return (ENOSPC);
+}
+
+/*
+ * Find a cylinder to place a directory.
+ *
+ * The policy implemented by this algorithm is to select from
+ * among those cylinder groups with above the average number of
+ * free inodes, the one with the smallest number of directories.
+ */
+ino_t
+dirpref(fs)
+       register struct fs *fs;
+{
+       int cg, minndir, mincg, avgifree;
+
+       avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg;
+       minndir = fs->fs_ipg;
+       mincg = 0;
+       for (cg = 0; cg < fs->fs_ncg; cg++)
+               if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
+                   fs->fs_cs(fs, cg).cs_nifree >= avgifree) {
+                       mincg = cg;
+                       minndir = fs->fs_cs(fs, cg).cs_ndir;
+               }
+       return ((ino_t)(fs->fs_ipg * mincg));
+}
+
+/*
+ * Select the desired position for the next block in a file.  The file is
+ * logically divided into sections. The first section is composed of the
+ * direct blocks. Each additional section contains fs_maxbpg blocks.
+ * 
+ * If no blocks have been allocated in the first section, the policy is to
+ * request a block in the same cylinder group as the inode that describes
+ * the file. If no blocks have been allocated in any other section, the
+ * policy is to place the section in a cylinder group with a greater than
+ * average number of free blocks.  An appropriate cylinder group is found
+ * by using a rotor that sweeps the cylinder groups. When a new group of
+ * blocks is needed, the sweep begins in the cylinder group following the
+ * cylinder group from which the previous allocation was made. The sweep
+ * continues until a cylinder group with greater than the average number
+ * of free blocks is found. If the allocation is for the first block in an
+ * indirect block, the information on the previous allocation is unavailable;
+ * here a best guess is made based upon the logical block number being
+ * allocated.
+ * 
+ * If a section is already partially allocated, the policy is to
+ * contiguously allocate fs_maxcontig blocks.  The end of one of these
+ * contiguous blocks and the beginning of the next is physically separated
+ * so that the disk head will be in transit between them for at least
+ * fs_rotdelay milliseconds.  This is to allow time for the processor to
+ * schedule another I/O transfer.
+ */
+daddr_t
+blkpref(ip, lbn, indx, bap)
+       struct inode *ip;
+       daddr_t lbn;
+       int indx;
+       daddr_t *bap;
+{
+       register struct fs *fs;
+       register int cg;
+       int avgbfree, startcg;
+       daddr_t nextblk;
+
+       fs = ip->i_fs;
+       if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
+               if (lbn < NDADDR) {
+                       cg = itog(fs, ip->i_number);
+                       return (fs->fs_fpg * cg + fs->fs_frag);
+               }
+               /*
+                * Find a cylinder with greater than average number of
+                * unused data blocks.
+                */
+               if (indx == 0 || bap[indx - 1] == 0)
+                       startcg = itog(fs, ip->i_number) + lbn / fs->fs_maxbpg;
+               else
+                       startcg = dtog(fs, bap[indx - 1]) + 1;
+               startcg %= fs->fs_ncg;
+               avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
+               for (cg = startcg; cg < fs->fs_ncg; cg++)
+                       if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+                               fs->fs_cgrotor = cg;
+                               return (fs->fs_fpg * cg + fs->fs_frag);
+                       }
+               for (cg = 0; cg <= startcg; cg++)
+                       if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+                               fs->fs_cgrotor = cg;
+                               return (fs->fs_fpg * cg + fs->fs_frag);
+                       }
+               return (NULL);
+       }
+       /*
+        * One or more previous blocks have been laid out. If less
+        * than fs_maxcontig previous blocks are contiguous, the
+        * next block is requested contiguously, otherwise it is
+        * requested rotationally delayed by fs_rotdelay milliseconds.
+        */
+       nextblk = bap[indx - 1] + fs->fs_frag;
+       if (indx > fs->fs_maxcontig &&
+           bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig)
+           != nextblk)
+               return (nextblk);
+       if (fs->fs_rotdelay != 0)
+               /*
+                * Here we convert ms of delay to frags as:
+                * (frags) = (ms) * (rev/sec) * (sect/rev) /
+                *      ((sect/frag) * (ms/sec))
+                * then round up to the next block.
+                */
+               nextblk += roundup(fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect /
+                   (NSPF(fs) * 1000), fs->fs_frag);
+       return (nextblk);
+}
+
+/*
+ * Implement the cylinder overflow algorithm.
+ *
+ * The policy implemented by this algorithm is:
+ *   1) allocate the block in its requested cylinder group.
+ *   2) quadradically rehash on the cylinder group number.
+ *   3) brute force search for a free block.
+ */
+/*VARARGS5*/
+u_long
+hashalloc(ip, cg, pref, size, allocator)
+       struct inode *ip;
+       int cg;
+       long pref;
+       int size;       /* size for data blocks, mode for inodes */
+       u_long (*allocator)();
+{
+       register struct fs *fs;
+       long result;
+       int i, icg = cg;
+
+       fs = ip->i_fs;
+       /*
+        * 1: preferred cylinder group
+        */
+       result = (*allocator)(ip, cg, pref, size);
+       if (result)
+               return (result);
+       /*
+        * 2: quadratic rehash
+        */
+       for (i = 1; i < fs->fs_ncg; i *= 2) {
+               cg += i;
+               if (cg >= fs->fs_ncg)
+                       cg -= fs->fs_ncg;
+               result = (*allocator)(ip, cg, 0, size);
+               if (result)
+                       return (result);
+       }
+       /*
+        * 3: brute force search
+        * Note that we start at i == 2, since 0 was checked initially,
+        * and 1 is always checked in the quadratic rehash.
+        */
+       cg = (icg + 2) % fs->fs_ncg;
+       for (i = 2; i < fs->fs_ncg; i++) {
+               result = (*allocator)(ip, cg, 0, size);
+               if (result)
+                       return (result);
+               cg++;
+               if (cg == fs->fs_ncg)
+                       cg = 0;
+       }
+       return (NULL);
+}
+
+/*
+ * Determine whether a fragment can be extended.
+ *
+ * Check to see if the necessary fragments are available, and 
+ * if they are, allocate them.
+ */
+daddr_t
+fragextend(ip, cg, bprev, osize, nsize)
+       struct inode *ip;
+       int cg;
+       long bprev;
+       int osize, nsize;
+{
+       register struct fs *fs;
+       register struct cg *cgp;
+       struct buf *bp;
+       long bno;
+       int frags, bbase;
+       int i, error;
+
+       fs = ip->i_fs;
+       if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
+               return (NULL);
+       frags = numfrags(fs, nsize);
+       bbase = fragnum(fs, bprev);
+       if (bbase > fragnum(fs, (bprev + frags - 1))) {
+               /* cannot extend across a block boundary */
+               return (NULL);
+       }
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, NOCRED, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
+       cgp = bp->b_un.b_cg;
+       if (!cg_chkmagic(cgp)) {
+               brelse(bp);
+               return (NULL);
+       }
+       cgp->cg_time = time.tv_sec;
+       bno = dtogd(fs, bprev);
+       for (i = numfrags(fs, osize); i < frags; i++)
+               if (isclr(cg_blksfree(cgp), bno + i)) {
+                       brelse(bp);
+                       return (NULL);
+               }
+       /*
+        * the current fragment can be extended
+        * deduct the count on fragment being extended into
+        * increase the count on the remaining fragment (if any)
+        * allocate the extended piece
+        */
+       for (i = frags; i < fs->fs_frag - bbase; i++)
+               if (isclr(cg_blksfree(cgp), bno + i))
+                       break;
+       cgp->cg_frsum[i - numfrags(fs, osize)]--;
+       if (i != frags)
+               cgp->cg_frsum[i - frags]++;
+       for (i = numfrags(fs, osize); i < frags; i++) {
+               clrbit(cg_blksfree(cgp), bno + i);
+               cgp->cg_cs.cs_nffree--;
+               fs->fs_cstotal.cs_nffree--;
+               fs->fs_cs(fs, cg).cs_nffree--;
+       }
+       fs->fs_fmod++;
+       bdwrite(bp);
+       return (bprev);
+}
+
+/*
+ * Determine whether a block can be allocated.
+ *
+ * Check to see if a block of the apprpriate size is available,
+ * and if it is, allocate it.
+ */
+daddr_t
+alloccg(ip, cg, bpref, size)
+       struct inode *ip;
+       int cg;
+       daddr_t bpref;
+       int size;
+{
+       register struct fs *fs;
+       register struct cg *cgp;
+       struct buf *bp;
+       register int i;
+       int error, bno, frags, allocsiz;
+
+       fs = ip->i_fs;
+       if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
+               return (NULL);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, NOCRED, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
+       cgp = bp->b_un.b_cg;
+       if (!cg_chkmagic(cgp) ||
+           (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
+               brelse(bp);
+               return (NULL);
+       }
+       cgp->cg_time = time.tv_sec;
+       if (size == fs->fs_bsize) {
+               bno = alloccgblk(fs, cgp, bpref);
+               bdwrite(bp);
+               return (bno);
+       }
+       /*
+        * check to see if any fragments are already available
+        * allocsiz is the size which will be allocated, hacking
+        * it down to a smaller size if necessary
+        */
+       frags = numfrags(fs, size);
+       for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
+               if (cgp->cg_frsum[allocsiz] != 0)
+                       break;
+       if (allocsiz == fs->fs_frag) {
+               /*
+                * no fragments were available, so a block will be 
+                * allocated, and hacked up
+                */
+               if (cgp->cg_cs.cs_nbfree == 0) {
+                       brelse(bp);
+                       return (NULL);
+               }
+               bno = alloccgblk(fs, cgp, bpref);
+               bpref = dtogd(fs, bno);
+               for (i = frags; i < fs->fs_frag; i++)
+                       setbit(cg_blksfree(cgp), bpref + i);
+               i = fs->fs_frag - frags;
+               cgp->cg_cs.cs_nffree += i;
+               fs->fs_cstotal.cs_nffree += i;
+               fs->fs_cs(fs, cg).cs_nffree += i;
+               fs->fs_fmod++;
+               cgp->cg_frsum[i]++;
+               bdwrite(bp);
+               return (bno);
+       }
+       bno = mapsearch(fs, cgp, bpref, allocsiz);
+       if (bno < 0) {
+               brelse(bp);
+               return (NULL);
+       }
+       for (i = 0; i < frags; i++)
+               clrbit(cg_blksfree(cgp), bno + i);
+       cgp->cg_cs.cs_nffree -= frags;
+       fs->fs_cstotal.cs_nffree -= frags;
+       fs->fs_cs(fs, cg).cs_nffree -= frags;
+       fs->fs_fmod++;
+       cgp->cg_frsum[allocsiz]--;
+       if (frags != allocsiz)
+               cgp->cg_frsum[allocsiz - frags]++;
+       bdwrite(bp);
+       return (cg * fs->fs_fpg + bno);
+}
+
+/*
+ * Allocate a block in a cylinder group.
+ *
+ * This algorithm implements the following policy:
+ *   1) allocate the requested block.
+ *   2) allocate a rotationally optimal block in the same cylinder.
+ *   3) allocate the next available block on the block rotor for the
+ *      specified cylinder group.
+ * Note that this routine only allocates fs_bsize blocks; these
+ * blocks may be fragmented by the routine that allocates them.
+ */
+daddr_t
+alloccgblk(fs, cgp, bpref)
+       register struct fs *fs;
+       register struct cg *cgp;
+       daddr_t bpref;
+{
+       daddr_t bno;
+       int cylno, pos, delta;
+       short *cylbp;
+       register int i;
+
+       if (bpref == 0) {
+               bpref = cgp->cg_rotor;
+               goto norot;
+       }
+       bpref = blknum(fs, bpref);
+       bpref = dtogd(fs, bpref);
+       /*
+        * if the requested block is available, use it
+        */
+       if (isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bpref))) {
+               bno = bpref;
+               goto gotit;
+       }
+       /*
+        * check for a block available on the same cylinder
+        */
+       cylno = cbtocylno(fs, bpref);
+       if (cg_blktot(cgp)[cylno] == 0)
+               goto norot;
+       if (fs->fs_cpc == 0) {
+               /*
+                * block layout info is not available, so just have
+                * to take any block in this cylinder.
+                */
+               bpref = howmany(fs->fs_spc * cylno, NSPF(fs));
+               goto norot;
+       }
+       /*
+        * check the summary information to see if a block is 
+        * available in the requested cylinder starting at the
+        * requested rotational position and proceeding around.
+        */
+       cylbp = cg_blks(fs, cgp, cylno);
+       pos = cbtorpos(fs, bpref);
+       for (i = pos; i < fs->fs_nrpos; i++)
+               if (cylbp[i] > 0)
+                       break;
+       if (i == fs->fs_nrpos)
+               for (i = 0; i < pos; i++)
+                       if (cylbp[i] > 0)
+                               break;
+       if (cylbp[i] > 0) {
+               /*
+                * found a rotational position, now find the actual
+                * block. A panic if none is actually there.
+                */
+               pos = cylno % fs->fs_cpc;
+               bno = (cylno - pos) * fs->fs_spc / NSPB(fs);
+               if (fs_postbl(fs, pos)[i] == -1) {
+                       printf("pos = %d, i = %d, fs = %s\n",
+                           pos, i, fs->fs_fsmnt);
+                       panic("alloccgblk: cyl groups corrupted");
+               }
+               for (i = fs_postbl(fs, pos)[i];; ) {
+                       if (isblock(fs, cg_blksfree(cgp), bno + i)) {
+                               bno = blkstofrags(fs, (bno + i));
+                               goto gotit;
+                       }
+                       delta = fs_rotbl(fs)[i];
+                       if (delta <= 0 ||
+                           delta + i > fragstoblks(fs, fs->fs_fpg))
+                               break;
+                       i += delta;
+               }
+               printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt);
+               panic("alloccgblk: can't find blk in cyl");
+       }
+norot:
+       /*
+        * no blocks in the requested cylinder, so take next
+        * available one in this cylinder group.
+        */
+       bno = mapsearch(fs, cgp, bpref, (int)fs->fs_frag);
+       if (bno < 0)
+               return (NULL);
+       cgp->cg_rotor = bno;
+gotit:
+       clrblock(fs, cg_blksfree(cgp), (long)fragstoblks(fs, bno));
+       cgp->cg_cs.cs_nbfree--;
+       fs->fs_cstotal.cs_nbfree--;
+       fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--;
+       cylno = cbtocylno(fs, bno);
+       cg_blks(fs, cgp, cylno)[cbtorpos(fs, bno)]--;
+       cg_blktot(cgp)[cylno]--;
+       fs->fs_fmod++;
+       return (cgp->cg_cgx * fs->fs_fpg + bno);
+}
+
+/*
+ * Determine whether an inode can be allocated.
+ *
+ * Check to see if an inode is available, and if it is,
+ * allocate it using the following policy:
+ *   1) allocate the requested inode.
+ *   2) allocate the next available inode after the requested
+ *      inode in the specified cylinder group.
+ */
+ino_t
+ialloccg(ip, cg, ipref, mode)
+       struct inode *ip;
+       int cg;
+       daddr_t ipref;
+       int mode;
+{
+       register struct fs *fs;
+       register struct cg *cgp;
+       struct buf *bp;
+       int error, start, len, loc, map, i;
+
+       fs = ip->i_fs;
+       if (fs->fs_cs(fs, cg).cs_nifree == 0)
+               return (NULL);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, NOCRED, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
+       cgp = bp->b_un.b_cg;
+       if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) {
+               brelse(bp);
+               return (NULL);
+       }
+       cgp->cg_time = time.tv_sec;
+       if (ipref) {
+               ipref %= fs->fs_ipg;
+               if (isclr(cg_inosused(cgp), ipref))
+                       goto gotit;
+       }
+       start = cgp->cg_irotor / NBBY;
+       len = howmany(fs->fs_ipg - cgp->cg_irotor, NBBY);
+       loc = skpc(0xff, len, &cg_inosused(cgp)[start]);
+       if (loc == 0) {
+               len = start + 1;
+               start = 0;
+               loc = skpc(0xff, len, &cg_inosused(cgp)[0]);
+               if (loc == 0) {
+                       printf("cg = %s, irotor = %d, fs = %s\n",
+                           cg, cgp->cg_irotor, fs->fs_fsmnt);
+                       panic("ialloccg: map corrupted");
+                       /* NOTREACHED */
+               }
+       }
+       i = start + len - loc;
+       map = cg_inosused(cgp)[i];
+       ipref = i * NBBY;
+       for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) {
+               if ((map & i) == 0) {
+                       cgp->cg_irotor = ipref;
+                       goto gotit;
+               }
+       }
+       printf("fs = %s\n", fs->fs_fsmnt);
+       panic("ialloccg: block not in map");
+       /* NOTREACHED */
+gotit:
+       setbit(cg_inosused(cgp), ipref);
+       cgp->cg_cs.cs_nifree--;
+       fs->fs_cstotal.cs_nifree--;
+       fs->fs_cs(fs, cg).cs_nifree--;
+       fs->fs_fmod++;
+       if ((mode & IFMT) == IFDIR) {
+               cgp->cg_cs.cs_ndir++;
+               fs->fs_cstotal.cs_ndir++;
+               fs->fs_cs(fs, cg).cs_ndir++;
+       }
+       bdwrite(bp);
+       return (cg * fs->fs_ipg + ipref);
+}
+
+/*
+ * Free a block or fragment.
+ *
+ * The specified block or fragment is placed back in the
+ * free map. If a fragment is deallocated, a possible 
+ * block reassembly is checked.
+ */
+blkfree(ip, bno, size)
+       register struct inode *ip;
+       daddr_t bno;
+       off_t size;
+{
+       register struct fs *fs;
+       register struct cg *cgp;
+       struct buf *bp;
+       int error, cg, blk, frags, bbase;
+       register int i;
+       struct ucred *cred = curproc->p_ucred;  /* XXX */
+
+       fs = ip->i_fs;
+       if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
+               printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
+                   ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
+               panic("blkfree: bad size");
+       }
+       cg = dtog(fs, bno);
+       if ((unsigned)bno >= fs->fs_size) {
+               printf("bad block %d, ino %d\n", bno, ip->i_number);
+               fserr(fs, cred->cr_uid, "bad block");
+               return;
+       }
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, NOCRED, &bp);
+       if (error) {
+               brelse(bp);
+               return;
+       }
+       cgp = bp->b_un.b_cg;
+       if (!cg_chkmagic(cgp)) {
+               brelse(bp);
+               return;
+       }
+       cgp->cg_time = time.tv_sec;
+       bno = dtogd(fs, bno);
+       if (size == fs->fs_bsize) {
+               if (isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno))) {
+                       printf("dev = 0x%x, block = %d, fs = %s\n",
+                           ip->i_dev, bno, fs->fs_fsmnt);
+                       panic("blkfree: freeing free block");
+               }
+               setblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno));
+               cgp->cg_cs.cs_nbfree++;
+               fs->fs_cstotal.cs_nbfree++;
+               fs->fs_cs(fs, cg).cs_nbfree++;
+               i = cbtocylno(fs, bno);
+               cg_blks(fs, cgp, i)[cbtorpos(fs, bno)]++;
+               cg_blktot(cgp)[i]++;
+       } else {
+               bbase = bno - fragnum(fs, bno);
+               /*
+                * decrement the counts associated with the old frags
+                */
+               blk = blkmap(fs, cg_blksfree(cgp), bbase);
+               fragacct(fs, blk, cgp->cg_frsum, -1);
+               /*
+                * deallocate the fragment
+                */
+               frags = numfrags(fs, size);
+               for (i = 0; i < frags; i++) {
+                       if (isset(cg_blksfree(cgp), bno + i)) {
+                               printf("dev = 0x%x, block = %d, fs = %s\n",
+                                   ip->i_dev, bno + i, fs->fs_fsmnt);
+                               panic("blkfree: freeing free frag");
+                       }
+                       setbit(cg_blksfree(cgp), bno + i);
+               }
+               cgp->cg_cs.cs_nffree += i;
+               fs->fs_cstotal.cs_nffree += i;
+               fs->fs_cs(fs, cg).cs_nffree += i;
+               /*
+                * add back in counts associated with the new frags
+                */
+               blk = blkmap(fs, cg_blksfree(cgp), bbase);
+               fragacct(fs, blk, cgp->cg_frsum, 1);
+               /*
+                * if a complete block has been reassembled, account for it
+                */
+               if (isblock(fs, cg_blksfree(cgp),
+                   (daddr_t)fragstoblks(fs, bbase))) {
+                       cgp->cg_cs.cs_nffree -= fs->fs_frag;
+                       fs->fs_cstotal.cs_nffree -= fs->fs_frag;
+                       fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
+                       cgp->cg_cs.cs_nbfree++;
+                       fs->fs_cstotal.cs_nbfree++;
+                       fs->fs_cs(fs, cg).cs_nbfree++;
+                       i = cbtocylno(fs, bbase);
+                       cg_blks(fs, cgp, i)[cbtorpos(fs, bbase)]++;
+                       cg_blktot(cgp)[i]++;
+               }
+       }
+       fs->fs_fmod++;
+       bdwrite(bp);
+}
+
+/*
+ * Free an inode.
+ *
+ * The specified inode is placed back in the free map.
+ */
+ifree(ip, ino, mode)
+       struct inode *ip;
+       ino_t ino;
+       int mode;
+{
+       register struct fs *fs;
+       register struct cg *cgp;
+       struct buf *bp;
+       int error, cg;
+
+       fs = ip->i_fs;
+       if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) {
+               printf("dev = 0x%x, ino = %d, fs = %s\n",
+                   ip->i_dev, ino, fs->fs_fsmnt);
+               panic("ifree: range");
+       }
+       cg = itog(fs, ino);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, NOCRED, &bp);
+       if (error) {
+               brelse(bp);
+               return;
+       }
+       cgp = bp->b_un.b_cg;
+       if (!cg_chkmagic(cgp)) {
+               brelse(bp);
+               return;
+       }
+       cgp->cg_time = time.tv_sec;
+       ino %= fs->fs_ipg;
+       if (isclr(cg_inosused(cgp), ino)) {
+               printf("dev = 0x%x, ino = %d, fs = %s\n",
+                   ip->i_dev, ino, fs->fs_fsmnt);
+               if (fs->fs_ronly == 0)
+                       panic("ifree: freeing free inode");
+       }
+       clrbit(cg_inosused(cgp), ino);
+       if (ino < cgp->cg_irotor)
+               cgp->cg_irotor = ino;
+       cgp->cg_cs.cs_nifree++;
+       fs->fs_cstotal.cs_nifree++;
+       fs->fs_cs(fs, cg).cs_nifree++;
+       if ((mode & IFMT) == IFDIR) {
+               cgp->cg_cs.cs_ndir--;
+               fs->fs_cstotal.cs_ndir--;
+               fs->fs_cs(fs, cg).cs_ndir--;
+       }
+       fs->fs_fmod++;
+       bdwrite(bp);
+}
+
+/*
+ * Find a block of the specified size in the specified cylinder group.
+ *
+ * It is a panic if a request is made to find a block if none are
+ * available.
+ */
+daddr_t
+mapsearch(fs, cgp, bpref, allocsiz)
+       register struct fs *fs;
+       register struct cg *cgp;
+       daddr_t bpref;
+       int allocsiz;
+{
+       daddr_t bno;
+       int start, len, loc, i;
+       int blk, field, subfield, pos;
+
+       /*
+        * find the fragment by searching through the free block
+        * map for an appropriate bit pattern
+        */
+       if (bpref)
+               start = dtogd(fs, bpref) / NBBY;
+       else
+               start = cgp->cg_frotor / NBBY;
+       len = howmany(fs->fs_fpg, NBBY) - start;
+       loc = scanc((unsigned)len, (u_char *)&cg_blksfree(cgp)[start],
+               (u_char *)fragtbl[fs->fs_frag],
+               (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
+       if (loc == 0) {
+               len = start + 1;
+               start = 0;
+               loc = scanc((unsigned)len, (u_char *)&cg_blksfree(cgp)[0],
+                       (u_char *)fragtbl[fs->fs_frag],
+                       (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
+               if (loc == 0) {
+                       printf("start = %d, len = %d, fs = %s\n",
+                           start, len, fs->fs_fsmnt);
+                       panic("alloccg: map corrupted");
+                       /* NOTREACHED */
+               }
+       }
+       bno = (start + len - loc) * NBBY;
+       cgp->cg_frotor = bno;
+       /*
+        * found the byte in the map
+        * sift through the bits to find the selected frag
+        */
+       for (i = bno + NBBY; bno < i; bno += fs->fs_frag) {
+               blk = blkmap(fs, cg_blksfree(cgp), bno);
+               blk <<= 1;
+               field = around[allocsiz];
+               subfield = inside[allocsiz];
+               for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) {
+                       if ((blk & field) == subfield)
+                               return (bno + pos);
+                       field <<= 1;
+                       subfield <<= 1;
+               }
+       }
+       printf("bno = %d, fs = %s\n", bno, fs->fs_fsmnt);
+       panic("alloccg: block not in map");
+       return (-1);
+}
+
+/*
+ * Fserr prints the name of a file system with an error diagnostic.
+ * 
+ * The form of the error message is:
+ *     fs: error message
+ */
+fserr(fs, uid, cp)
+       struct fs *fs;
+       uid_t uid;
+       char *cp;
+{
+
+       log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp);
+}
diff --git a/usr/src/sys.386bsd/ufs/ufs_bmap.c b/usr/src/sys.386bsd/ufs/ufs_bmap.c
new file mode 100644 (file)
index 0000000..cc0a23b
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_bmap.c  7.13 (Berkeley) 5/8/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "proc.h"
+#include "file.h"
+#include "vnode.h"
+
+#include "quota.h"
+#include "inode.h"
+#include "fs.h"
+
+/*
+ * Bmap converts a the logical block number of a file
+ * to its physical block number on the disk. The conversion
+ * is done by using the logical block number to index into
+ * the array of block pointers described by the dinode.
+ */
+bmap(ip, bn, bnp)
+       register struct inode *ip;
+       register daddr_t bn;
+       daddr_t *bnp;
+{
+       register struct fs *fs;
+       register daddr_t nb;
+       struct buf *bp;
+       daddr_t *bap;
+       int i, j, sh;
+       int error;
+
+       if (bn < 0)
+               return (EFBIG);
+       fs = ip->i_fs;
+
+       /*
+        * The first NDADDR blocks are direct blocks
+        */
+       if (bn < NDADDR) {
+               nb = ip->i_db[bn];
+               if (nb == 0) {
+                       *bnp = (daddr_t)-1;
+                       return (0);
+               }
+               *bnp = fsbtodb(fs, nb);
+               return (0);
+       }
+       /*
+        * Determine the number of levels of indirection.
+        */
+       sh = 1;
+       bn -= NDADDR;
+       for (j = NIADDR; j > 0; j--) {
+               sh *= NINDIR(fs);
+               if (bn < sh)
+                       break;
+               bn -= sh;
+       }
+       if (j == 0)
+               return (EFBIG);
+       /*
+        * Fetch through the indirect blocks.
+        */
+       nb = ip->i_ib[NIADDR - j];
+       if (nb == 0) {
+               *bnp = (daddr_t)-1;
+               return (0);
+       }
+       for (; j <= NIADDR; j++) {
+               if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
+                   (int)fs->fs_bsize, NOCRED, &bp)) {
+                       brelse(bp);
+                       return (error);
+               }
+               bap = bp->b_un.b_daddr;
+               sh /= NINDIR(fs);
+               i = (bn / sh) % NINDIR(fs);
+               nb = bap[i];
+               if (nb == 0) {
+                       *bnp = (daddr_t)-1;
+                       brelse(bp);
+                       return (0);
+               }
+               brelse(bp);
+       }
+       *bnp = fsbtodb(fs, nb);
+       return (0);
+}
+
+/*
+ * Balloc defines the structure of file system storage
+ * by allocating the physical blocks on a device given
+ * the inode and the logical block number in a file.
+ */
+balloc(ip, bn, size, bpp, flags)
+       register struct inode *ip;
+       register daddr_t bn;
+       int size;
+       struct buf **bpp;
+       int flags;
+{
+       register struct fs *fs;
+       register daddr_t nb;
+       struct buf *bp, *nbp;
+       struct vnode *vp = ITOV(ip);
+       int osize, nsize, i, j, sh, error;
+       daddr_t newb, lbn, *bap, pref, blkpref();
+
+       *bpp = (struct buf *)0;
+       if (bn < 0)
+               return (EFBIG);
+       fs = ip->i_fs;
+
+       /*
+        * If the next write will extend the file into a new block,
+        * and the file is currently composed of a fragment
+        * this fragment has to be extended to be a full block.
+        */
+       nb = lblkno(fs, ip->i_size);
+       if (nb < NDADDR && nb < bn) {
+               osize = blksize(fs, ip, nb);
+               if (osize < fs->fs_bsize && osize > 0) {
+                       error = realloccg(ip, nb,
+                               blkpref(ip, nb, (int)nb, &ip->i_db[0]),
+                               osize, (int)fs->fs_bsize, &bp);
+                       if (error)
+                               return (error);
+                       ip->i_size = (nb + 1) * fs->fs_bsize;
+                       vnode_pager_setsize(ITOV(ip), (u_long)ip->i_size);
+                       ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
+                       ip->i_flag |= IUPD|ICHG;
+                       if (flags & B_SYNC)
+                               bwrite(bp);
+                       else
+                               bawrite(bp);
+               }
+       }
+       /*
+        * The first NDADDR blocks are direct blocks
+        */
+       if (bn < NDADDR) {
+               nb = ip->i_db[bn];
+               if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
+                       error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
+                       if (error) {
+                               brelse(bp);
+                               return (error);
+                       }
+                       *bpp = bp;
+                       return (0);
+               }
+               if (nb != 0) {
+                       /*
+                        * Consider need to reallocate a fragment.
+                        */
+                       osize = fragroundup(fs, blkoff(fs, ip->i_size));
+                       nsize = fragroundup(fs, size);
+                       if (nsize <= osize) {
+                               error = bread(vp, bn, osize, NOCRED, &bp);
+                               if (error) {
+                                       brelse(bp);
+                                       return (error);
+                               }
+                       } else {
+                               error = realloccg(ip, bn,
+                                       blkpref(ip, bn, (int)bn, &ip->i_db[0]),
+                                       osize, nsize, &bp);
+                               if (error)
+                                       return (error);
+                       }
+               } else {
+                       if (ip->i_size < (bn + 1) * fs->fs_bsize)
+                               nsize = fragroundup(fs, size);
+                       else
+                               nsize = fs->fs_bsize;
+                       error = alloc(ip, bn,
+                               blkpref(ip, bn, (int)bn, &ip->i_db[0]),
+                               nsize, &newb);
+                       if (error)
+                               return (error);
+                       bp = getblk(vp, bn, nsize);
+                       bp->b_blkno = fsbtodb(fs, newb);
+                       if (flags & B_CLRBUF)
+                               clrbuf(bp);
+               }
+               ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
+               ip->i_flag |= IUPD|ICHG;
+               *bpp = bp;
+               return (0);
+       }
+       /*
+        * Determine the number of levels of indirection.
+        */
+       pref = 0;
+       sh = 1;
+       lbn = bn;
+       bn -= NDADDR;
+       for (j = NIADDR; j > 0; j--) {
+               sh *= NINDIR(fs);
+               if (bn < sh)
+                       break;
+               bn -= sh;
+       }
+       if (j == 0)
+               return (EFBIG);
+       /*
+        * Fetch the first indirect block allocating if necessary.
+        */
+       nb = ip->i_ib[NIADDR - j];
+       if (nb == 0) {
+               pref = blkpref(ip, lbn, 0, (daddr_t *)0);
+               if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
+                       return (error);
+               nb = newb;
+               bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
+               clrbuf(bp);
+               /*
+                * Write synchronously so that indirect blocks
+                * never point at garbage.
+                */
+               if (error = bwrite(bp)) {
+                       blkfree(ip, nb, fs->fs_bsize);
+                       return (error);
+               }
+               ip->i_ib[NIADDR - j] = nb;
+               ip->i_flag |= IUPD|ICHG;
+       }
+       /*
+        * Fetch through the indirect blocks, allocating as necessary.
+        */
+       for (; ; j++) {
+               error = bread(ip->i_devvp, fsbtodb(fs, nb),
+                   (int)fs->fs_bsize, NOCRED, &bp);
+               if (error) {
+                       brelse(bp);
+                       return (error);
+               }
+               bap = bp->b_un.b_daddr;
+               sh /= NINDIR(fs);
+               i = (bn / sh) % NINDIR(fs);
+               nb = bap[i];
+               if (j == NIADDR)
+                       break;
+               if (nb != 0) {
+                       brelse(bp);
+                       continue;
+               }
+               if (pref == 0)
+                       pref = blkpref(ip, lbn, 0, (daddr_t *)0);
+               if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
+                       brelse(bp);
+                       return (error);
+               }
+               nb = newb;
+               nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
+               clrbuf(nbp);
+               /*
+                * Write synchronously so that indirect blocks
+                * never point at garbage.
+                */
+               if (error = bwrite(nbp)) {
+                       blkfree(ip, nb, fs->fs_bsize);
+                       brelse(bp);
+                       return (error);
+               }
+               bap[i] = nb;
+               /*
+                * If required, write synchronously, otherwise use
+                * delayed write. If this is the first instance of
+                * the delayed write, reassociate the buffer with the
+                * file so it will be written if the file is sync'ed.
+                */
+               if (flags & B_SYNC) {
+                       bwrite(bp);
+               } else if (bp->b_flags & B_DELWRI) {
+                       bdwrite(bp);
+               } else {
+                       bdwrite(bp);
+                       reassignbuf(bp, vp);
+               }
+       }
+       /*
+        * Get the data block, allocating if necessary.
+        */
+       if (nb == 0) {
+               pref = blkpref(ip, lbn, i, &bap[0]);
+               if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
+                       brelse(bp);
+                       return (error);
+               }
+               nb = newb;
+               nbp = getblk(vp, lbn, fs->fs_bsize);
+               nbp->b_blkno = fsbtodb(fs, nb);
+               if (flags & B_CLRBUF)
+                       clrbuf(nbp);
+               bap[i] = nb;
+               /*
+                * If required, write synchronously, otherwise use
+                * delayed write. If this is the first instance of
+                * the delayed write, reassociate the buffer with the
+                * file so it will be written if the file is sync'ed.
+                */
+               if (flags & B_SYNC) {
+                       bwrite(bp);
+               } else if (bp->b_flags & B_DELWRI) {
+                       bdwrite(bp);
+               } else {
+                       bdwrite(bp);
+                       reassignbuf(bp, vp);
+               }
+               *bpp = nbp;
+               return (0);
+       }
+       brelse(bp);
+       if (flags & B_CLRBUF) {
+               error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
+               if (error) {
+                       brelse(nbp);
+                       return (error);
+               }
+       } else {
+               nbp = getblk(vp, lbn, fs->fs_bsize);
+               nbp->b_blkno = fsbtodb(fs, nb);
+       }
+       *bpp = nbp;
+       return (0);
+}
diff --git a/usr/src/sys.386bsd/ufs/ufs_inode.c b/usr/src/sys.386bsd/ufs/ufs_inode.c
new file mode 100644 (file)
index 0000000..34eaa76
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_inode.c 7.40 (Berkeley) 5/8/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "mount.h"
+#include "proc.h"
+#include "file.h"
+#include "buf.h"
+#include "vnode.h"
+#include "kernel.h"
+#include "malloc.h"
+
+#include "quota.h"
+#include "inode.h"
+#include "fs.h"
+#include "ufsmount.h"
+
+#define        INOHSZ  512
+#if    ((INOHSZ&(INOHSZ-1)) == 0)
+#define        INOHASH(dev,ino)        (((dev)+(ino))&(INOHSZ-1))
+#else
+#define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
+#endif
+
+union ihead {
+       union  ihead *ih_head[2];
+       struct inode *ih_chain[2];
+} ihead[INOHSZ];
+
+int prtactive; /* 1 => print out reclaim of active vnodes */
+
+/*
+ * Initialize hash links for inodes.
+ */
+ufs_init()
+{
+       register int i;
+       register union ihead *ih = ihead;
+
+#ifndef lint
+       if (VN_MAXPRIVATE < sizeof(struct inode))
+               panic("ihinit: too small");
+#endif /* not lint */
+       for (i = INOHSZ; --i >= 0; ih++) {
+               ih->ih_head[0] = ih;
+               ih->ih_head[1] = ih;
+       }
+#ifdef QUOTA
+       dqinit();
+#endif /* QUOTA */
+}
+
+/*
+ * Look up a UFS dinode number to find its incore vnode.
+ * If it is not in core, read it in from the specified device.
+ * If it is in core, wait for the lock bit to clear, then
+ * return the inode locked. Detection and handling of mount
+ * points must be done by the calling routine.
+ */
+iget(xp, ino, ipp)
+       struct inode *xp;
+       ino_t ino;
+       struct inode **ipp;
+{
+       dev_t dev = xp->i_dev;
+       struct mount *mntp = ITOV(xp)->v_mount;
+       register struct fs *fs = VFSTOUFS(mntp)->um_fs;
+       extern struct vnodeops ufs_vnodeops, spec_inodeops;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+       struct vnode *nvp;
+       struct buf *bp;
+       struct dinode *dp;
+       union ihead *ih;
+       int i, error;
+
+       ih = &ihead[INOHASH(dev, ino)];
+loop:
+       for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) {
+               if (ino != ip->i_number || dev != ip->i_dev)
+                       continue;
+               if ((ip->i_flag&ILOCKED) != 0) {
+                       ip->i_flag |= IWANT;
+                       sleep((caddr_t)ip, PINOD);
+                       goto loop;
+               }
+               if (vget(ITOV(ip)))
+                       goto loop;
+               *ipp = ip;
+               return(0);
+       }
+       /*
+        * Allocate a new inode.
+        */
+       if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) {
+               *ipp = 0;
+               return (error);
+       }
+       ip = VTOI(nvp);
+       ip->i_vnode = nvp;
+       ip->i_flag = 0;
+       ip->i_devvp = 0;
+       ip->i_mode = 0;
+       ip->i_diroff = 0;
+       ip->i_lockf = 0;
+#ifdef QUOTA
+       for (i = 0; i < MAXQUOTAS; i++)
+               ip->i_dquot[i] = NODQUOT;
+#endif
+       /*
+        * Put it onto its hash chain and lock it so that other requests for
+        * this inode will block if they arrive while we are sleeping waiting
+        * for old data structures to be purged or for the contents of the
+        * disk portion of this inode to be read.
+        */
+       ip->i_dev = dev;
+       ip->i_number = ino;
+       insque(ip, ih);
+       ILOCK(ip);
+       /*
+        * Read in the disk contents for the inode.
+        */
+       if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
+           (int)fs->fs_bsize, NOCRED, &bp)) {
+               /*
+                * The inode does not contain anything useful, so it would
+                * be misleading to leave it on its hash chain.
+                * Iput() will take care of putting it back on the free list.
+                */
+               remque(ip);
+               ip->i_forw = ip;
+               ip->i_back = ip;
+               /*
+                * Unlock and discard unneeded inode.
+                */
+               iput(ip);
+               brelse(bp);
+               *ipp = 0;
+               return (error);
+       }
+       dp = bp->b_un.b_dino;
+       dp += itoo(fs, ino);
+       ip->i_din = *dp;
+       brelse(bp);
+       /*
+        * Initialize the associated vnode
+        */
+       vp = ITOV(ip);
+       vp->v_type = IFTOVT(ip->i_mode);
+       if (vp->v_type == VFIFO) {
+#ifdef FIFO
+               extern struct vnodeops fifo_inodeops;
+               vp->v_op = &fifo_inodeops;
+#else
+               iput(ip);
+               *ipp = 0;
+               return (EOPNOTSUPP);
+#endif /* FIFO */
+       }
+       if (vp->v_type == VCHR || vp->v_type == VBLK) {
+               vp->v_op = &spec_inodeops;
+               if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
+                       /*
+                        * Reinitialize aliased inode.
+                        */
+                       vp = nvp;
+                       iq = VTOI(vp);
+                       iq->i_vnode = vp;
+                       iq->i_flag = 0;
+                       ILOCK(iq);
+                       iq->i_din = ip->i_din;
+                       iq->i_dev = dev;
+                       iq->i_number = ino;
+                       insque(iq, ih);
+                       /*
+                        * Discard unneeded vnode
+                        */
+                       ip->i_mode = 0;
+                       iput(ip);
+                       ip = iq;
+               }
+       }
+       if (ino == ROOTINO)
+               vp->v_flag |= VROOT;
+       /*
+        * Finish inode initialization.
+        */
+       ip->i_fs = fs;
+       ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
+       VREF(ip->i_devvp);
+       /*
+        * Set up a generation number for this inode if it does not
+        * already have one. This should only happen on old filesystems.
+        */
+       if (ip->i_gen == 0) {
+               if (++nextgennumber < (u_long)time.tv_sec)
+                       nextgennumber = time.tv_sec;
+               ip->i_gen = nextgennumber;
+               if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
+                       ip->i_flag |= IMOD;
+       }
+       *ipp = ip;
+       return (0);
+}
+
+/*
+ * Unlock and decrement the reference count of an inode structure.
+ */
+iput(ip)
+       register struct inode *ip;
+{
+
+       if ((ip->i_flag & ILOCKED) == 0)
+               panic("iput");
+       IUNLOCK(ip);
+       vrele(ITOV(ip));
+}
+
+/*
+ * Last reference to an inode, write the inode out and if necessary,
+ * truncate and deallocate the file.
+ */
+ufs_inactive(vp, p)
+       struct vnode *vp;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+       int mode, error = 0;
+
+       if (prtactive && vp->v_usecount != 0)
+               vprint("ufs_inactive: pushing active", vp);
+       /*
+        * Get rid of inodes related to stale file handles.
+        */
+       if (ip->i_mode == 0) {
+               if ((vp->v_flag & VXLOCK) == 0)
+                       vgone(vp);
+               return (0);
+       }
+       ILOCK(ip);
+       if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
+#ifdef QUOTA
+               if (!getinoquota(ip))
+                       (void) chkiq(ip, -1, NOCRED, 0);
+#endif
+               error = itrunc(ip, (u_long)0, 0);
+               mode = ip->i_mode;
+               ip->i_mode = 0;
+               ip->i_rdev = 0;
+               ip->i_flag |= IUPD|ICHG;
+               ifree(ip, ip->i_number, mode);
+       }
+       IUPDAT(ip, &time, &time, 0);
+       IUNLOCK(ip);
+       ip->i_flag = 0;
+       /*
+        * If we are done with the inode, reclaim it
+        * so that it can be reused immediately.
+        */
+       if (vp->v_usecount == 0 && ip->i_mode == 0)
+               vgone(vp);
+       return (error);
+}
+
+/*
+ * Reclaim an inode so that it can be used for other purposes.
+ */
+ufs_reclaim(vp)
+       register struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+       int i;
+
+       if (prtactive && vp->v_usecount != 0)
+               vprint("ufs_reclaim: pushing active", vp);
+       /*
+        * Remove the inode from its hash chain.
+        */
+       remque(ip);
+       ip->i_forw = ip;
+       ip->i_back = ip;
+       /*
+        * Purge old data structures associated with the inode.
+        */
+       cache_purge(vp);
+       if (ip->i_devvp) {
+               vrele(ip->i_devvp);
+               ip->i_devvp = 0;
+       }
+#ifdef QUOTA
+       for (i = 0; i < MAXQUOTAS; i++) {
+               if (ip->i_dquot[i] != NODQUOT) {
+                       dqrele(vp, ip->i_dquot[i]);
+                       ip->i_dquot[i] = NODQUOT;
+               }
+       }
+#endif
+       ip->i_flag = 0;
+       return (0);
+}
+
+/*
+ * Update the access, modified, and inode change times as specified
+ * by the IACC, IMOD, and ICHG flags respectively. The IUPD flag
+ * is used to specify that the inode needs to be updated but that
+ * the times have already been set. The access and modified times
+ * are taken from the second and third parameters; the inode change
+ * time is always taken from the current time. If waitfor is set,
+ * then wait for the disk write of the inode to complete.
+ */
+iupdat(ip, ta, tm, waitfor)
+       register struct inode *ip;
+       struct timeval *ta, *tm;
+       int waitfor;
+{
+       struct buf *bp;
+       struct vnode *vp = ITOV(ip);
+       struct dinode *dp;
+       register struct fs *fs;
+       int error;
+
+       fs = ip->i_fs;
+       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
+               return (0);
+       if (vp->v_mount->mnt_flag & MNT_RDONLY)
+               return (0);
+       error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
+               (int)fs->fs_bsize, NOCRED, &bp);
+       if (error) {
+               brelse(bp);
+               return (error);
+       }
+       if (ip->i_flag&IACC)
+               ip->i_atime = ta->tv_sec;
+       if (ip->i_flag&IUPD)
+               ip->i_mtime = tm->tv_sec;
+       if (ip->i_flag&ICHG)
+               ip->i_ctime = time.tv_sec;
+       ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
+       dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
+       *dp = ip->i_din;
+       if (waitfor) {
+               return (bwrite(bp));
+       } else {
+               bdwrite(bp);
+               return (0);
+       }
+}
+
+#define        SINGLE  0       /* index of single indirect block */
+#define        DOUBLE  1       /* index of double indirect block */
+#define        TRIPLE  2       /* index of triple indirect block */
+/*
+ * Truncate the inode ip to at most length size.  Free affected disk
+ * blocks -- the blocks of the file are removed in reverse order.
+ *
+ * NB: triple indirect blocks are untested.
+ */
+itrunc(oip, length, flags)
+       register struct inode *oip;
+       u_long length;
+       int flags;
+{
+       register daddr_t lastblock;
+       daddr_t bn, lbn, lastiblock[NIADDR];
+       register struct fs *fs;
+       register struct inode *ip;
+       struct buf *bp;
+       int offset, osize, size, level;
+       long count, nblocks, blocksreleased = 0;
+       register int i;
+       int aflags, error, allerror;
+       struct inode tip;
+
+       vnode_pager_setsize(ITOV(oip), length);
+       if (oip->i_size <= length) {
+               oip->i_flag |= ICHG|IUPD;
+               error = iupdat(oip, &time, &time, 1);
+               return (error);
+       }
+       /*
+        * Calculate index into inode's block list of
+        * last direct and indirect blocks (if any)
+        * which we want to keep.  Lastblock is -1 when
+        * the file is truncated to 0.
+        */
+       fs = oip->i_fs;
+       lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
+       lastiblock[SINGLE] = lastblock - NDADDR;
+       lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
+       lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
+       nblocks = btodb(fs->fs_bsize);
+       /*
+        * Update the size of the file. If the file is not being
+        * truncated to a block boundry, the contents of the
+        * partial block following the end of the file must be
+        * zero'ed in case it ever become accessable again because
+        * of subsequent file growth.
+        */
+       osize = oip->i_size;
+       offset = blkoff(fs, length);
+       if (offset == 0) {
+               oip->i_size = length;
+       } else {
+               lbn = lblkno(fs, length);
+               aflags = B_CLRBUF;
+               if (flags & IO_SYNC)
+                       aflags |= B_SYNC;
+#ifdef QUOTA
+               if (error = getinoquota(oip))
+                       return (error);
+#endif
+               if (error = balloc(oip, lbn, offset, &bp, aflags))
+                       return (error);
+               oip->i_size = length;
+               size = blksize(fs, oip, lbn);
+               (void) vnode_pager_uncache(ITOV(oip));
+               bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
+               allocbuf(bp, size);
+               if (flags & IO_SYNC)
+                       bwrite(bp);
+               else
+                       bdwrite(bp);
+       }
+       /*
+        * Update file and block pointers
+        * on disk before we start freeing blocks.
+        * If we crash before free'ing blocks below,
+        * the blocks will be returned to the free list.
+        * lastiblock values are also normalized to -1
+        * for calls to indirtrunc below.
+        */
+       tip = *oip;
+       tip.i_size = osize;
+       for (level = TRIPLE; level >= SINGLE; level--)
+               if (lastiblock[level] < 0) {
+                       oip->i_ib[level] = 0;
+                       lastiblock[level] = -1;
+               }
+       for (i = NDADDR - 1; i > lastblock; i--)
+               oip->i_db[i] = 0;
+       oip->i_flag |= ICHG|IUPD;
+       vinvalbuf(ITOV(oip), (length > 0));
+       allerror = iupdat(oip, &time, &time, MNT_WAIT);
+
+       /*
+        * Indirect blocks first.
+        */
+       ip = &tip;
+       for (level = TRIPLE; level >= SINGLE; level--) {
+               bn = ip->i_ib[level];
+               if (bn != 0) {
+                       error = indirtrunc(ip, bn, lastiblock[level], level,
+                               &count);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += count;
+                       if (lastiblock[level] < 0) {
+                               ip->i_ib[level] = 0;
+                               blkfree(ip, bn, (off_t)fs->fs_bsize);
+                               blocksreleased += nblocks;
+                       }
+               }
+               if (lastiblock[level] >= 0)
+                       goto done;
+       }
+
+       /*
+        * All whole direct blocks or frags.
+        */
+       for (i = NDADDR - 1; i > lastblock; i--) {
+               register off_t bsize;
+
+               bn = ip->i_db[i];
+               if (bn == 0)
+                       continue;
+               ip->i_db[i] = 0;
+               bsize = (off_t)blksize(fs, ip, i);
+               blkfree(ip, bn, bsize);
+               blocksreleased += btodb(bsize);
+       }
+       if (lastblock < 0)
+               goto done;
+
+       /*
+        * Finally, look for a change in size of the
+        * last direct block; release any frags.
+        */
+       bn = ip->i_db[lastblock];
+       if (bn != 0) {
+               off_t oldspace, newspace;
+
+               /*
+                * Calculate amount of space we're giving
+                * back as old block size minus new block size.
+                */
+               oldspace = blksize(fs, ip, lastblock);
+               ip->i_size = length;
+               newspace = blksize(fs, ip, lastblock);
+               if (newspace == 0)
+                       panic("itrunc: newspace");
+               if (oldspace - newspace > 0) {
+                       /*
+                        * Block number of space to be free'd is
+                        * the old block # plus the number of frags
+                        * required for the storage we're keeping.
+                        */
+                       bn += numfrags(fs, newspace);
+                       blkfree(ip, bn, oldspace - newspace);
+                       blocksreleased += btodb(oldspace - newspace);
+               }
+       }
+done:
+/* BEGIN PARANOIA */
+       for (level = SINGLE; level <= TRIPLE; level++)
+               if (ip->i_ib[level] != oip->i_ib[level])
+                       panic("itrunc1");
+       for (i = 0; i < NDADDR; i++)
+               if (ip->i_db[i] != oip->i_db[i])
+                       panic("itrunc2");
+/* END PARANOIA */
+       oip->i_blocks -= blocksreleased;
+       if (oip->i_blocks < 0)                  /* sanity */
+               oip->i_blocks = 0;
+       oip->i_flag |= ICHG;
+#ifdef QUOTA
+       if (!getinoquota(oip))
+               (void) chkdq(oip, -blocksreleased, NOCRED, 0);
+#endif
+       return (allerror);
+}
+
+/*
+ * Release blocks associated with the inode ip and
+ * stored in the indirect block bn.  Blocks are free'd
+ * in LIFO order up to (but not including) lastbn.  If
+ * level is greater than SINGLE, the block is an indirect
+ * block and recursive calls to indirtrunc must be used to
+ * cleanse other indirect blocks.
+ *
+ * NB: triple indirect blocks are untested.
+ */
+indirtrunc(ip, bn, lastbn, level, countp)
+       register struct inode *ip;
+       daddr_t bn, lastbn;
+       int level;
+       long *countp;
+{
+       register int i;
+       struct buf *bp;
+       register struct fs *fs = ip->i_fs;
+       register daddr_t *bap;
+       daddr_t *copy, nb, last;
+       long blkcount, factor;
+       int nblocks, blocksreleased = 0;
+       int error, allerror = 0;
+
+       /*
+        * Calculate index in current block of last
+        * block to be kept.  -1 indicates the entire
+        * block so we need not calculate the index.
+        */
+       factor = 1;
+       for (i = SINGLE; i < level; i++)
+               factor *= NINDIR(fs);
+       last = lastbn;
+       if (lastbn > 0)
+               last /= factor;
+       nblocks = btodb(fs->fs_bsize);
+       /*
+        * Get buffer of block pointers, zero those 
+        * entries corresponding to blocks to be free'd,
+        * and update on disk copy first.
+        */
+       error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize,
+               NOCRED, &bp);
+       if (error) {
+               brelse(bp);
+               *countp = 0;
+               return (error);
+       }
+       bap = bp->b_un.b_daddr;
+       MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
+       bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
+       bzero((caddr_t)&bap[last + 1],
+         (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
+       if (last == -1)
+               bp->b_flags |= B_INVAL;
+       error = bwrite(bp);
+       if (error)
+               allerror = error;
+       bap = copy;
+
+       /*
+        * Recursively free totally unused blocks.
+        */
+       for (i = NINDIR(fs) - 1; i > last; i--) {
+               nb = bap[i];
+               if (nb == 0)
+                       continue;
+               if (level > SINGLE) {
+                       error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
+                               &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
+               blkfree(ip, nb, (off_t)fs->fs_bsize);
+               blocksreleased += nblocks;
+       }
+
+       /*
+        * Recursively free last partial block.
+        */
+       if (level > SINGLE && lastbn >= 0) {
+               last = lastbn % factor;
+               nb = bap[i];
+               if (nb != 0) {
+                       error = indirtrunc(ip, nb, last, level - 1, &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
+       }
+       FREE(copy, M_TEMP);
+       *countp = blocksreleased;
+       return (allerror);
+}
+
+/*
+ * Lock an inode. If its already locked, set the WANT bit and sleep.
+ */
+ilock(ip)
+       register struct inode *ip;
+{
+
+       while (ip->i_flag & ILOCKED) {
+               ip->i_flag |= IWANT;
+               if (ip->i_spare0 == curproc->p_pid)
+                       panic("locking against myself");
+               ip->i_spare1 = curproc->p_pid;
+               (void) sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_spare1 = 0;
+       ip->i_spare0 = curproc->p_pid;
+       ip->i_flag |= ILOCKED;
+}
+
+/*
+ * Unlock an inode.  If WANT bit is on, wakeup.
+ */
+iunlock(ip)
+       register struct inode *ip;
+{
+
+       if ((ip->i_flag & ILOCKED) == 0)
+               vprint("iunlock: unlocked inode", ITOV(ip));
+       ip->i_spare0 = 0;
+       ip->i_flag &= ~ILOCKED;
+       if (ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
diff --git a/usr/src/sys.386bsd/ufs/ufs_quota.c b/usr/src/sys.386bsd/ufs/ufs_quota.c
new file mode 100644 (file)
index 0000000..3813d2d
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_quota.c 7.11 (Berkeley) 6/21/91
+ */
+#include "param.h"
+#include "kernel.h"
+#include "systm.h"
+#include "namei.h"
+#include "malloc.h"
+#include "file.h"
+#include "proc.h"
+#include "vnode.h"
+#include "mount.h"
+
+#include "fs.h"
+#include "quota.h"
+#include "inode.h"
+#include "ufsmount.h"
+
+/*
+ * Quota name to error message mapping.
+ */
+static char *quotatypes[] = INITQFNAMES;
+
+/*
+ * Set up the quotas for an inode.
+ *
+ * This routine completely defines the semantics of quotas.
+ * If other criterion want to be used to establish quotas, the
+ * MAXQUOTAS value in quotas.h should be increased, and the
+ * additional dquots set up here.
+ */
+getinoquota(ip)
+       register struct inode *ip;
+{
+       struct ufsmount *ump;
+       struct vnode *vp = ITOV(ip);
+       int error;
+
+       ump = VFSTOUFS(vp->v_mount);
+       /*
+        * Set up the user quota based on file uid.
+        * EINVAL means that quotas are not enabled.
+        */
+       if (ip->i_dquot[USRQUOTA] == NODQUOT &&
+           (error =
+               dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
+           error != EINVAL)
+               return (error);
+       /*
+        * Set up the group quota based on file gid.
+        * EINVAL means that quotas are not enabled.
+        */
+       if (ip->i_dquot[GRPQUOTA] == NODQUOT &&
+           (error =
+               dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) &&
+           error != EINVAL)
+               return (error);
+       return (0);
+}
+
+/*
+ * Update disk usage, and take corrective action.
+ */
+chkdq(ip, change, cred, flags)
+       register struct inode *ip;
+       long change;
+       struct ucred *cred;
+       int flags;
+{
+       register struct dquot *dq;
+       register int i;
+       int ncurblocks, error;
+
+#ifdef DIAGNOSTIC
+       if ((flags & CHOWN) == 0)
+               chkdquot(ip);
+#endif
+       if (change == 0)
+               return (0);
+       if (change < 0) {
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if ((dq = ip->i_dquot[i]) == NODQUOT)
+                               continue;
+                       while (dq->dq_flags & DQ_LOCK) {
+                               dq->dq_flags |= DQ_WANT;
+                               sleep((caddr_t)dq, PINOD+1);
+                       }
+                       ncurblocks = dq->dq_curblocks + change;
+                       if (ncurblocks >= 0)
+                               dq->dq_curblocks = ncurblocks;
+                       else
+                               dq->dq_curblocks = 0;
+                       dq->dq_flags &= ~DQ_BLKS;
+                       dq->dq_flags |= DQ_MOD;
+               }
+               return (0);
+       }
+       if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if ((dq = ip->i_dquot[i]) == NODQUOT)
+                               continue;
+                       if (error = chkdqchg(ip, change, cred, i))
+                               return (error);
+               }
+       }
+       for (i = 0; i < MAXQUOTAS; i++) {
+               if ((dq = ip->i_dquot[i]) == NODQUOT)
+                       continue;
+               while (dq->dq_flags & DQ_LOCK) {
+                       dq->dq_flags |= DQ_WANT;
+                       sleep((caddr_t)dq, PINOD+1);
+               }
+               dq->dq_curblocks += change;
+               dq->dq_flags |= DQ_MOD;
+       }
+       return (0);
+}
+
+/*
+ * Check for a valid change to a users allocation.
+ * Issue an error message if appropriate.
+ */
+chkdqchg(ip, change, cred, type)
+       struct inode *ip;
+       long change;
+       struct ucred *cred;
+       int type;
+{
+       register struct dquot *dq = ip->i_dquot[type];
+       long ncurblocks = dq->dq_curblocks + change;
+
+       /*
+        * If user would exceed their hard limit, disallow space allocation.
+        */
+       if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
+               if ((dq->dq_flags & DQ_BLKS) == 0 &&
+                   ip->i_uid == cred->cr_uid) {
+                       uprintf("\n%s: write failed, %s disk limit reached\n",
+                           ip->i_fs->fs_fsmnt, quotatypes[type]);
+                       dq->dq_flags |= DQ_BLKS;
+               }
+               return (EDQUOT);
+       }
+       /*
+        * If user is over their soft limit for too long, disallow space
+        * allocation. Reset time limit as they cross their soft limit.
+        */
+       if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
+               if (dq->dq_curblocks < dq->dq_bsoftlimit) {
+                       dq->dq_btime = time.tv_sec +
+                           VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type];
+                       if (ip->i_uid == cred->cr_uid)
+                               uprintf("\n%s: warning, %s %s\n",
+                                   ip->i_fs->fs_fsmnt, quotatypes[type],
+                                   "disk quota exceeded");
+                       return (0);
+               }
+               if (time.tv_sec > dq->dq_btime) {
+                       if ((dq->dq_flags & DQ_BLKS) == 0 &&
+                           ip->i_uid == cred->cr_uid) {
+                               uprintf("\n%s: write failed, %s %s\n",
+                                   ip->i_fs->fs_fsmnt, quotatypes[type],
+                                   "disk quota exceeded too long");
+                               dq->dq_flags |= DQ_BLKS;
+                       }
+                       return (EDQUOT);
+               }
+       }
+       return (0);
+}
+
+/*
+ * Check the inode limit, applying corrective action.
+ */
+chkiq(ip, change, cred, flags)
+       register struct inode *ip;
+       long change;
+       struct ucred *cred;
+       int flags;
+{
+       register struct dquot *dq;
+       register int i;
+       int ncurinodes, error;
+
+#ifdef DIAGNOSTIC
+       if ((flags & CHOWN) == 0)
+               chkdquot(ip);
+#endif
+       if (change == 0)
+               return (0);
+       if (change < 0) {
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if ((dq = ip->i_dquot[i]) == NODQUOT)
+                               continue;
+                       while (dq->dq_flags & DQ_LOCK) {
+                               dq->dq_flags |= DQ_WANT;
+                               sleep((caddr_t)dq, PINOD+1);
+                       }
+                       ncurinodes = dq->dq_curinodes + change;
+                       if (ncurinodes >= 0)
+                               dq->dq_curinodes = ncurinodes;
+                       else
+                               dq->dq_curinodes = 0;
+                       dq->dq_flags &= ~DQ_INODS;
+                       dq->dq_flags |= DQ_MOD;
+               }
+               return (0);
+       }
+       if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if ((dq = ip->i_dquot[i]) == NODQUOT)
+                               continue;
+                       if (error = chkiqchg(ip, change, cred, i))
+                               return (error);
+               }
+       }
+       for (i = 0; i < MAXQUOTAS; i++) {
+               if ((dq = ip->i_dquot[i]) == NODQUOT)
+                       continue;
+               while (dq->dq_flags & DQ_LOCK) {
+                       dq->dq_flags |= DQ_WANT;
+                       sleep((caddr_t)dq, PINOD+1);
+               }
+               dq->dq_curinodes += change;
+               dq->dq_flags |= DQ_MOD;
+       }
+       return (0);
+}
+
+/*
+ * Check for a valid change to a users allocation.
+ * Issue an error message if appropriate.
+ */
+chkiqchg(ip, change, cred, type)
+       struct inode *ip;
+       long change;
+       struct ucred *cred;
+       int type;
+{
+       register struct dquot *dq = ip->i_dquot[type];
+       long ncurinodes = dq->dq_curinodes + change;
+
+       /*
+        * If user would exceed their hard limit, disallow inode allocation.
+        */
+       if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
+               if ((dq->dq_flags & DQ_INODS) == 0 &&
+                   ip->i_uid == cred->cr_uid) {
+                       uprintf("\n%s: write failed, %s inode limit reached\n",
+                           ip->i_fs->fs_fsmnt, quotatypes[type]);
+                       dq->dq_flags |= DQ_INODS;
+               }
+               return (EDQUOT);
+       }
+       /*
+        * If user is over their soft limit for too long, disallow inode
+        * allocation. Reset time limit as they cross their soft limit.
+        */
+       if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
+               if (dq->dq_curinodes < dq->dq_isoftlimit) {
+                       dq->dq_itime = time.tv_sec +
+                           VFSTOUFS(ITOV(ip)->v_mount)->um_itime[type];
+                       if (ip->i_uid == cred->cr_uid)
+                               uprintf("\n%s: warning, %s %s\n",
+                                   ip->i_fs->fs_fsmnt, quotatypes[type],
+                                   "inode quota exceeded");
+                       return (0);
+               }
+               if (time.tv_sec > dq->dq_itime) {
+                       if ((dq->dq_flags & DQ_INODS) == 0 &&
+                           ip->i_uid == cred->cr_uid) {
+                               uprintf("\n%s: write failed, %s %s\n",
+                                   ip->i_fs->fs_fsmnt, quotatypes[type],
+                                   "inode quota exceeded too long");
+                               dq->dq_flags |= DQ_INODS;
+                       }
+                       return (EDQUOT);
+               }
+       }
+       return (0);
+}
+
+#ifdef DIAGNOSTIC
+/*
+ * On filesystems with quotas enabled,
+ * it is an error for a file to change size and not
+ * to have a dquot structure associated with it.
+ */
+chkdquot(ip)
+       register struct inode *ip;
+{
+       struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount);
+       register int i;
+
+       for (i = 0; i < MAXQUOTAS; i++) {
+               if (ump->um_quotas[i] == NULLVP ||
+                   (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
+                       continue;
+               if (ip->i_dquot[i] == NODQUOT) {
+                       vprint("chkdquot: missing dquot", ITOV(ip));
+                       panic("missing dquot");
+               }
+       }
+}
+#endif /* DIAGNOSTIC */
+
+/*
+ * Code to process quotactl commands.
+ */
+
+/*
+ * Q_QUOTAON - set up a quota file for a particular file system.
+ */
+quotaon(p, mp, type, fname)
+       struct proc *p;
+       struct mount *mp;
+       register int type;
+       caddr_t fname;
+{
+       register struct ufsmount *ump = VFSTOUFS(mp);
+       register struct vnode *vp, **vpp;
+       struct vnode *nextvp;
+       struct dquot *dq;
+       int error;
+       struct nameidata nd;
+
+       vpp = &ump->um_quotas[type];
+       nd.ni_segflg = UIO_USERSPACE;
+       nd.ni_dirp = fname;
+       if (error = vn_open(&nd, p, FREAD|FWRITE, 0))
+               return (error);
+       vp = nd.ni_vp;
+       VOP_UNLOCK(vp);
+       if (vp->v_type != VREG) {
+               (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
+               return (EACCES);
+       }
+       if (vfs_busy(mp)) {
+               (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
+               return (EBUSY);
+       }
+       if (*vpp != vp)
+               quotaoff(p, mp, type);
+       ump->um_qflags[type] |= QTF_OPENING;
+       mp->mnt_flag |= MNT_QUOTA;
+       vp->v_flag |= VSYSTEM;
+       *vpp = vp;
+       /*
+        * Save the credential of the process that turned on quotas.
+        * Set up the time limits for this quota.
+        */
+       crhold(p->p_ucred);
+       ump->um_cred[type] = p->p_ucred;
+       ump->um_btime[type] = MAX_DQ_TIME;
+       ump->um_itime[type] = MAX_IQ_TIME;
+       if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
+               if (dq->dq_btime > 0)
+                       ump->um_btime[type] = dq->dq_btime;
+               if (dq->dq_itime > 0)
+                       ump->um_itime[type] = dq->dq_itime;
+               dqrele(NULLVP, dq);
+       }
+       /*
+        * Search vnodes associated with this mount point,
+        * adding references to quota file being opened.
+        * NB: only need to add dquot's for inodes being modified.
+        */
+again:
+       for (vp = mp->mnt_mounth; vp; vp = nextvp) {
+               nextvp = vp->v_mountf;
+               if (vp->v_writecount == 0)
+                       continue;
+               if (vget(vp))
+                       goto again;
+               if (error = getinoquota(VTOI(vp))) {
+                       vput(vp);
+                       break;
+               }
+               vput(vp);
+               if (vp->v_mountf != nextvp || vp->v_mount != mp)
+                       goto again;
+       }
+       ump->um_qflags[type] &= ~QTF_OPENING;
+       if (error)
+               quotaoff(p, mp, type);
+       vfs_unbusy(mp);
+       return (error);
+}
+
+/*
+ * Q_QUOTAOFF - turn off disk quotas for a filesystem.
+ */
+quotaoff(p, mp, type)
+       struct proc *p;
+       struct mount *mp;
+       register int type;
+{
+       register struct vnode *vp;
+       struct vnode *qvp, *nextvp;
+       struct ufsmount *ump = VFSTOUFS(mp);
+       register struct dquot *dq;
+       register struct inode *ip;
+       int error;
+       
+       if ((mp->mnt_flag & MNT_MPBUSY) == 0)
+               panic("quotaoff: not busy");
+       if ((qvp = ump->um_quotas[type]) == NULLVP)
+               return (0);
+       ump->um_qflags[type] |= QTF_CLOSING;
+       /*
+        * Search vnodes associated with this mount point,
+        * deleting any references to quota file being closed.
+        */
+again:
+       for (vp = mp->mnt_mounth; vp; vp = nextvp) {
+               nextvp = vp->v_mountf;
+               if (vget(vp))
+                       goto again;
+               ip = VTOI(vp);
+               dq = ip->i_dquot[type];
+               ip->i_dquot[type] = NODQUOT;
+               dqrele(vp, dq);
+               vput(vp);
+               if (vp->v_mountf != nextvp || vp->v_mount != mp)
+                       goto again;
+       }
+       dqflush(qvp);
+       qvp->v_flag &= ~VSYSTEM;
+       error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p);
+       ump->um_quotas[type] = NULLVP;
+       crfree(ump->um_cred[type]);
+       ump->um_cred[type] = NOCRED;
+       ump->um_qflags[type] &= ~QTF_CLOSING;
+       for (type = 0; type < MAXQUOTAS; type++)
+               if (ump->um_quotas[type] != NULLVP)
+                       break;
+       if (type == MAXQUOTAS)
+               mp->mnt_flag &= ~MNT_QUOTA;
+       return (error);
+}
+
+/*
+ * Q_GETQUOTA - return current values in a dqblk structure.
+ */
+getquota(mp, id, type, addr)
+       struct mount *mp;
+       u_long id;
+       int type;
+       caddr_t addr;
+{
+       struct dquot *dq;
+       int error;
+
+       if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq))
+               return (error);
+       error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk));
+       dqrele(NULLVP, dq);
+       return (error);
+}
+
+/*
+ * Q_SETQUOTA - assign an entire dqblk structure.
+ */
+setquota(mp, id, type, addr)
+       struct mount *mp;
+       u_long id;
+       int type;
+       caddr_t addr;
+{
+       register struct dquot *dq;
+       struct dquot *ndq;
+       struct ufsmount *ump = VFSTOUFS(mp);
+       struct dqblk newlim;
+       int error;
+
+       if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)))
+               return (error);
+       if (error = dqget(NULLVP, id, ump, type, &ndq))
+               return (error);
+       dq = ndq;
+       while (dq->dq_flags & DQ_LOCK) {
+               dq->dq_flags |= DQ_WANT;
+               sleep((caddr_t)dq, PINOD+1);
+       }
+       /*
+        * Copy all but the current values.
+        * Reset time limit if previously had no soft limit or were
+        * under it, but now have a soft limit and are over it.
+        */
+       newlim.dqb_curblocks = dq->dq_curblocks;
+       newlim.dqb_curinodes = dq->dq_curinodes;
+       if (dq->dq_id != 0) {
+               newlim.dqb_btime = dq->dq_btime;
+               newlim.dqb_itime = dq->dq_itime;
+       }
+       if (newlim.dqb_bsoftlimit &&
+           dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
+           (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
+               newlim.dqb_btime = time.tv_sec + ump->um_btime[type];
+       if (newlim.dqb_isoftlimit &&
+           dq->dq_curinodes >= newlim.dqb_isoftlimit &&
+           (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
+               newlim.dqb_itime = time.tv_sec + ump->um_itime[type];
+       dq->dq_dqb = newlim;
+       if (dq->dq_curblocks < dq->dq_bsoftlimit)
+               dq->dq_flags &= ~DQ_BLKS;
+       if (dq->dq_curinodes < dq->dq_isoftlimit)
+               dq->dq_flags &= ~DQ_INODS;
+       if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
+           dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
+               dq->dq_flags |= DQ_FAKE;
+       else
+               dq->dq_flags &= ~DQ_FAKE;
+       dq->dq_flags |= DQ_MOD;
+       dqrele(NULLVP, dq);
+       return (0);
+}
+
+/*
+ * Q_SETUSE - set current inode and block usage.
+ */
+setuse(mp, id, type, addr)
+       struct mount *mp;
+       u_long id;
+       int type;
+       caddr_t addr;
+{
+       register struct dquot *dq;
+       struct ufsmount *ump = VFSTOUFS(mp);
+       struct dquot *ndq;
+       struct dqblk usage;
+       int error;
+
+       if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)))
+               return (error);
+       if (error = dqget(NULLVP, id, ump, type, &ndq))
+               return (error);
+       dq = ndq;
+       while (dq->dq_flags & DQ_LOCK) {
+               dq->dq_flags |= DQ_WANT;
+               sleep((caddr_t)dq, PINOD+1);
+       }
+       /*
+        * Reset time limit if have a soft limit and were
+        * previously under it, but are now over it.
+        */
+       if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
+           usage.dqb_curblocks >= dq->dq_bsoftlimit)
+               dq->dq_btime = time.tv_sec + ump->um_btime[type];
+       if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
+           usage.dqb_curinodes >= dq->dq_isoftlimit)
+               dq->dq_itime = time.tv_sec + ump->um_itime[type];
+       dq->dq_curblocks = usage.dqb_curblocks;
+       dq->dq_curinodes = usage.dqb_curinodes;
+       if (dq->dq_curblocks < dq->dq_bsoftlimit)
+               dq->dq_flags &= ~DQ_BLKS;
+       if (dq->dq_curinodes < dq->dq_isoftlimit)
+               dq->dq_flags &= ~DQ_INODS;
+       dq->dq_flags |= DQ_MOD;
+       dqrele(NULLVP, dq);
+       return (0);
+}
+
+/*
+ * Q_SYNC - sync quota files to disk.
+ */
+qsync(mp)
+       struct mount *mp;
+{
+       struct ufsmount *ump = VFSTOUFS(mp);
+       register struct vnode *vp, *nextvp;
+       register struct dquot *dq;
+       register int i;
+
+       /*
+        * Check if the mount point has any quotas.
+        * If not, simply return.
+        */
+       if ((mp->mnt_flag & MNT_MPBUSY) == 0)
+               panic("qsync: not busy");
+       for (i = 0; i < MAXQUOTAS; i++)
+               if (ump->um_quotas[i] != NULLVP)
+                       break;
+       if (i == MAXQUOTAS)
+               return (0);
+       /*
+        * Search vnodes associated with this mount point,
+        * synchronizing any modified dquot structures.
+        */
+again:
+       for (vp = mp->mnt_mounth; vp; vp = nextvp) {
+               nextvp = vp->v_mountf;
+               if (VOP_ISLOCKED(vp))
+                       continue;
+               if (vget(vp))
+                       goto again;
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       dq = VTOI(vp)->i_dquot[i];
+                       if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))
+                               dqsync(vp, dq);
+               }
+               vput(vp);
+               if (vp->v_mountf != nextvp || vp->v_mount != mp)
+                       goto again;
+       }
+       return (0);
+}
+
+/*
+ * Code pertaining to management of the in-core dquot data structures.
+ */
+
+/*
+ * Dquot cache - hash chain headers.
+ */
+union  dqhead  {
+       union   dqhead  *dqh_head[2];
+       struct  dquot   *dqh_chain[2];
+};
+#define        dqh_forw        dqh_chain[0]
+#define        dqh_back        dqh_chain[1]
+
+union dqhead *dqhashtbl;
+long dqhash;
+
+/*
+ * Dquot free list.
+ */
+#define        DQUOTINC        5       /* minimum free dquots desired */
+struct dquot *dqfreel, **dqback = &dqfreel;
+long numdquot, desireddquot = DQUOTINC;
+
+/*
+ * Initialize the quota system.
+ */
+dqinit()
+{
+       register union dqhead *dhp;
+       register long dqhashsize;
+
+       dqhashsize = roundup((desiredvnodes + 1) * sizeof *dhp / 2,
+               NBPG * CLSIZE);
+       dqhashtbl = (union dqhead *)malloc(dqhashsize, M_DQUOT, M_WAITOK);
+       for (dqhash = 1; dqhash <= dqhashsize / sizeof *dhp; dqhash <<= 1)
+               /* void */;
+       dqhash = (dqhash >> 1) - 1;
+       for (dhp = &dqhashtbl[dqhash]; dhp >= dqhashtbl; dhp--) {
+               dhp->dqh_head[0] = dhp;
+               dhp->dqh_head[1] = dhp;
+       }
+}
+
+/*
+ * Obtain a dquot structure for the specified identifier and quota file
+ * reading the information from the file if necessary.
+ */
+dqget(vp, id, ump, type, dqp)
+       struct vnode *vp;
+       u_long id;
+       register struct ufsmount *ump;
+       register int type;
+       struct dquot **dqp;
+{
+       register struct dquot *dq;
+       register union dqhead *dh;
+       register struct dquot *dp;
+       register struct vnode *dqvp;
+       struct iovec aiov;
+       struct uio auio;
+       int error;
+
+       dqvp = ump->um_quotas[type];
+       if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
+               *dqp = NODQUOT;
+               return (EINVAL);
+       }
+       /*
+        * Check the cache first.
+        */
+       dh = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash];
+       for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = dq->dq_forw) {
+               if (dq->dq_id != id ||
+                   dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
+                       continue;
+               /*
+                * Cache hit with no references.  Take
+                * the structure off the free list.
+                */
+               if (dq->dq_cnt == 0) {
+                       dp = dq->dq_freef;
+                       if (dp != NODQUOT)
+                               dp->dq_freeb = dq->dq_freeb;
+                       else
+                               dqback = dq->dq_freeb;
+                       *dq->dq_freeb = dp;
+               }
+               DQREF(dq);
+               *dqp = dq;
+               return (0);
+       }
+       /*
+        * Not in cache, allocate a new one.
+        */
+       if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes)
+               desireddquot += DQUOTINC;
+       if (numdquot < desireddquot) {
+               dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK);
+               bzero((char *)dq, sizeof *dq);
+               numdquot++;
+       } else {
+               if ((dq = dqfreel) == NULL) {
+                       tablefull("dquot");
+                       *dqp = NODQUOT;
+                       return (EUSERS);
+               }
+               if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
+                       panic("free dquot isn't");
+               if ((dp = dq->dq_freef) != NODQUOT)
+                       dp->dq_freeb = &dqfreel;
+               else
+                       dqback = &dqfreel;
+               dqfreel = dp;
+               dq->dq_freef = NULL;
+               dq->dq_freeb = NULL;
+               remque(dq);
+       }
+       /*
+        * Initialize the contents of the dquot structure.
+        */
+       if (vp != dqvp)
+               VOP_LOCK(dqvp);
+       insque(dq, dh);
+       DQREF(dq);
+       dq->dq_flags = DQ_LOCK;
+       dq->dq_id = id;
+       dq->dq_ump = ump;
+       dq->dq_type = type;
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       aiov.iov_base = (caddr_t)&dq->dq_dqb;
+       aiov.iov_len = sizeof (struct dqblk);
+       auio.uio_resid = sizeof (struct dqblk);
+       auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
+       auio.uio_segflg = UIO_SYSSPACE;
+       auio.uio_rw = UIO_READ;
+       auio.uio_procp = (struct proc *)0;
+       error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
+       if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
+               bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk));
+       if (vp != dqvp)
+               VOP_UNLOCK(dqvp);
+       if (dq->dq_flags & DQ_WANT)
+               wakeup((caddr_t)dq);
+       dq->dq_flags = 0;
+       /*
+        * I/O error in reading quota file, release
+        * quota structure and reflect problem to caller.
+        */
+       if (error) {
+               remque(dq);
+               dq->dq_forw = dq;       /* on a private, unfindable hash list */
+               dq->dq_back = dq;
+               dqrele(vp, dq);
+               *dqp = NODQUOT;
+               return (error);
+       }
+       /*
+        * Check for no limit to enforce.
+        * Initialize time values if necessary.
+        */
+       if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
+           dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
+               dq->dq_flags |= DQ_FAKE;
+       if (dq->dq_id != 0) {
+               if (dq->dq_btime == 0)
+                       dq->dq_btime = time.tv_sec + ump->um_btime[type];
+               if (dq->dq_itime == 0)
+                       dq->dq_itime = time.tv_sec + ump->um_itime[type];
+       }
+       *dqp = dq;
+       return (0);
+}
+
+/*
+ * Obtain a reference to a dquot.
+ */
+dqref(dq)
+       struct dquot *dq;
+{
+
+       dq->dq_cnt++;
+}
+
+/*
+ * Release a reference to a dquot.
+ */
+dqrele(vp, dq)
+       struct vnode *vp;
+       register struct dquot *dq;
+{
+
+       if (dq == NODQUOT)
+               return;
+       if (dq->dq_cnt > 1) {
+               dq->dq_cnt--;
+               return;
+       }
+       if (dq->dq_flags & DQ_MOD)
+               (void) dqsync(vp, dq);
+       if (--dq->dq_cnt > 0)
+               return;
+       if (dqfreel != NODQUOT) {
+               *dqback = dq;
+               dq->dq_freeb = dqback;
+       } else {
+               dqfreel = dq;
+               dq->dq_freeb = &dqfreel;
+       }
+       dq->dq_freef = NODQUOT;
+       dqback = &dq->dq_freef;
+}
+
+/*
+ * Update the disk quota in the quota file.
+ */
+dqsync(vp, dq)
+       struct vnode *vp;
+       register struct dquot *dq;
+{
+       struct vnode *dqvp;
+       struct iovec aiov;
+       struct uio auio;
+       int error;
+
+       if (dq == NODQUOT)
+               panic("dqsync: dquot");
+       if ((dq->dq_flags & DQ_MOD) == 0)
+               return (0);
+       if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
+               panic("dqsync: file");
+       if (vp != dqvp)
+               VOP_LOCK(dqvp);
+       while (dq->dq_flags & DQ_LOCK) {
+               dq->dq_flags |= DQ_WANT;
+               sleep((caddr_t)dq, PINOD+2);
+               if ((dq->dq_flags & DQ_MOD) == 0) {
+                       if (vp != dqvp)
+                               VOP_UNLOCK(dqvp);
+                       return (0);
+               }
+       }
+       dq->dq_flags |= DQ_LOCK;
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       aiov.iov_base = (caddr_t)&dq->dq_dqb;
+       aiov.iov_len = sizeof (struct dqblk);
+       auio.uio_resid = sizeof (struct dqblk);
+       auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
+       auio.uio_segflg = UIO_SYSSPACE;
+       auio.uio_rw = UIO_WRITE;
+       auio.uio_procp = (struct proc *)0;
+       error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
+       if (auio.uio_resid && error == 0)
+               error = EIO;
+       if (dq->dq_flags & DQ_WANT)
+               wakeup((caddr_t)dq);
+       dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT);
+       if (vp != dqvp)
+               VOP_UNLOCK(dqvp);
+       return (error);
+}
+
+/*
+ * Flush all entries from the cache for a particular vnode.
+ */
+dqflush(vp)
+       register struct vnode *vp;
+{
+       register union dqhead *dh;
+       register struct dquot *dq, *nextdq;
+
+       /*
+        * Move all dquot's that used to refer to this quota
+        * file off their hash chains (they will eventually
+        * fall off the head of the free list and be re-used).
+        */
+       for (dh = &dqhashtbl[dqhash]; dh >= dqhashtbl; dh--) {
+               for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = nextdq) {
+                       nextdq = dq->dq_forw;
+                       if (dq->dq_ump->um_quotas[dq->dq_type] != vp)
+                               continue;
+                       if (dq->dq_cnt)
+                               panic("dqflush: stray dquot");
+                       remque(dq);
+                       dq->dq_forw = dq;
+                       dq->dq_back = dq;
+                       dq->dq_ump = (struct ufsmount *)0;
+               }
+       }
+}
diff --git a/usr/src/sys.386bsd/ufs/ufs_subr.c b/usr/src/sys.386bsd/ufs/ufs_subr.c
new file mode 100644 (file)
index 0000000..9a730d5
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_subr.c  7.13 (Berkeley) 6/28/90
+ */
+
+#ifdef KERNEL
+#include "param.h"
+#include "../ufs/fs.h"
+#else
+#include <sys/param.h>
+#include <ufs/fs.h>
+#endif
+
+extern int around[9];
+extern int inside[9];
+extern u_char *fragtbl[];
+
+/*
+ * Update the frsum fields to reflect addition or deletion 
+ * of some frags.
+ */
+fragacct(fs, fragmap, fraglist, cnt)
+       struct fs *fs;
+       int fragmap;
+       long fraglist[];
+       int cnt;
+{
+       int inblk;
+       register int field, subfield;
+       register int siz, pos;
+
+       inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
+       fragmap <<= 1;
+       for (siz = 1; siz < fs->fs_frag; siz++) {
+               if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
+                       continue;
+               field = around[siz];
+               subfield = inside[siz];
+               for (pos = siz; pos <= fs->fs_frag; pos++) {
+                       if ((fragmap & field) == subfield) {
+                               fraglist[siz] += cnt;
+                               pos += siz;
+                               field <<= siz;
+                               subfield <<= siz;
+                       }
+                       field <<= 1;
+                       subfield <<= 1;
+               }
+       }
+}
+
+/*
+ * block operations
+ *
+ * check if a block is available
+ */
+isblock(fs, cp, h)
+       struct fs *fs;
+       unsigned char *cp;
+       daddr_t h;
+{
+       unsigned char mask;
+
+       switch ((int)fs->fs_frag) {
+       case 8:
+               return (cp[h] == 0xff);
+       case 4:
+               mask = 0x0f << ((h & 0x1) << 2);
+               return ((cp[h >> 1] & mask) == mask);
+       case 2:
+               mask = 0x03 << ((h & 0x3) << 1);
+               return ((cp[h >> 2] & mask) == mask);
+       case 1:
+               mask = 0x01 << (h & 0x7);
+               return ((cp[h >> 3] & mask) == mask);
+       default:
+               panic("isblock");
+               return (NULL);
+       }
+}
+
+/*
+ * take a block out of the map
+ */
+clrblock(fs, cp, h)
+       struct fs *fs;
+       u_char *cp;
+       daddr_t h;
+{
+
+       switch ((int)fs->fs_frag) {
+       case 8:
+               cp[h] = 0;
+               return;
+       case 4:
+               cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
+               return;
+       case 2:
+               cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
+               return;
+       case 1:
+               cp[h >> 3] &= ~(0x01 << (h & 0x7));
+               return;
+       default:
+               panic("clrblock");
+       }
+}
+
+/*
+ * put a block into the map
+ */
+setblock(fs, cp, h)
+       struct fs *fs;
+       unsigned char *cp;
+       daddr_t h;
+{
+
+       switch ((int)fs->fs_frag) {
+
+       case 8:
+               cp[h] = 0xff;
+               return;
+       case 4:
+               cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
+               return;
+       case 2:
+               cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
+               return;
+       case 1:
+               cp[h >> 3] |= (0x01 << (h & 0x7));
+               return;
+       default:
+               panic("setblock");
+       }
+}
+
+#if (!defined(vax) && !defined(tahoe) && !defined(hp300)) \
+       || defined(VAX630) || defined(VAX650)
+/*
+ * C definitions of special instructions.
+ * Normally expanded with inline.
+ */
+scanc(size, cp, table, mask)
+       u_int size;
+       register u_char *cp, table[];
+       register u_char mask;
+{
+       register u_char *end = &cp[size];
+
+       while (cp < end && (table[*cp] & mask) == 0)
+               cp++;
+       return (end - cp);
+}
+#endif
+
+#if !defined(vax) && !defined(tahoe) && !defined(hp300)
+skpc(mask, size, cp)
+       register u_char mask;
+       u_int size;
+       register u_char *cp;
+{
+       register u_char *end = &cp[size];
+
+       while (cp < end && *cp == mask)
+               cp++;
+       return (end - cp);
+}
+
+locc(mask, size, cp)
+       register u_char mask;
+       u_int size;
+       register u_char *cp;
+{
+       register u_char *end = &cp[size];
+
+       while (cp < end && *cp != mask)
+               cp++;
+       return (end - cp);
+}
+#endif
diff --git a/usr/src/sys.386bsd/ufs/ufs_tables.c b/usr/src/sys.386bsd/ufs/ufs_tables.c
new file mode 100644 (file)
index 0000000..1903e7c
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_tables.c        7.4 (Berkeley) 6/28/90
+ */
+
+#ifdef KERNEL
+#include "param.h"
+#else
+#include <sys/param.h>
+#endif
+
+/*
+ * Bit patterns for identifying fragments in the block map
+ * used as ((map & around) == inside)
+ */
+int around[9] = {
+       0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
+};
+int inside[9] = {
+       0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
+};
+
+/*
+ * Given a block map bit pattern, the frag tables tell whether a
+ * particular size fragment is available. 
+ *
+ * used as:
+ * if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] {
+ *     at least one fragment of the indicated size is available
+ * }
+ *
+ * These tables are used by the scanc instruction on the VAX to
+ * quickly find an appropriate fragment.
+ */
+u_char fragtbl124[256] = {
+       0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e,
+       0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e,
+       0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae,
+       0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
+       0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
+       0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
+       0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
+       0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
+       0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce,
+       0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a,
+};
+
+u_char fragtbl8[256] = {
+       0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04,
+       0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
+       0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+       0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
+       0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
+       0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
+       0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
+       0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
+       0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
+       0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
+       0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12,
+       0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
+       0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c,
+       0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c,
+       0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
+};
+
+/*
+ * The actual fragtbl array.
+ */
+u_char *fragtbl[MAXFRAG + 1] = {
+       0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8,
+};
diff --git a/usr/src/sys.386bsd/ufs/ufs_vnops.c b/usr/src/sys.386bsd/ufs/ufs_vnops.c
new file mode 100644 (file)
index 0000000..785a6c5
--- /dev/null
@@ -0,0 +1,1863 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_vnops.c 7.64 (Berkeley) 5/16/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "namei.h"
+#include "resourcevar.h"
+#include "kernel.h"
+#include "file.h"
+#include "stat.h"
+#include "buf.h"
+#include "proc.h"
+#include "conf.h"
+#include "mount.h"
+#include "vnode.h"
+#include "specdev.h"
+#include "fifo.h"
+#include "malloc.h"
+
+#include "lockf.h"
+#include "quota.h"
+#include "inode.h"
+#include "dir.h"
+#include "fs.h"
+
+/*
+ * Create a regular file
+ */
+ufs_create(ndp, vap, p)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       struct proc *p;
+{
+       struct inode *ip;
+       int error;
+
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       ndp->ni_vp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Mknod vnode call
+ */
+/* ARGSUSED */
+ufs_mknod(ndp, vap, cred, p)
+       struct nameidata *ndp;
+       struct ucred *cred;
+       struct vattr *vap;
+       struct proc *p;
+{
+       register struct vnode *vp;
+       struct inode *ip;
+       int error;
+
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       ip->i_flag |= IACC|IUPD|ICHG;
+       if (vap->va_rdev != VNOVAL) {
+               /*
+                * Want to be able to use this to make badblock
+                * inodes, so don't truncate the dev number.
+                */
+               ip->i_rdev = vap->va_rdev;
+       }
+       /*
+        * Remove inode so that it will be reloaded by iget and
+        * checked to see if it is an alias of an existing entry
+        * in the inode cache.
+        */
+       vp = ITOV(ip);
+       vput(vp);
+       vp->v_type = VNON;
+       vgone(vp);
+       return (0);
+}
+
+/*
+ * Open called.
+ *
+ * Nothing to do.
+ */
+/* ARGSUSED */
+ufs_open(vp, mode, cred, p)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
+       struct proc *p;
+{
+
+       return (0);
+}
+
+/*
+ * Close called
+ *
+ * Update the times on the inode.
+ */
+/* ARGSUSED */
+ufs_close(vp, fflag, cred, p)
+       struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+               ITIMES(ip, &time, &time);
+       return (0);
+}
+
+/*
+ * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
+ * The mode is shifted to select the owner/group/other fields. The
+ * super user is granted all permissions.
+ */
+ufs_access(vp, mode, cred, p)
+       struct vnode *vp;
+       register int mode;
+       struct ucred *cred;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+       register gid_t *gp;
+       int i, error;
+
+#ifdef DIAGNOSTIC
+       if (!VOP_ISLOCKED(vp)) {
+               vprint("ufs_access: not locked", vp);
+               panic("ufs_access: not locked");
+       }
+#endif
+#ifdef QUOTA
+       if (mode & VWRITE) {
+               switch (vp->v_type) {
+               case VREG: case VDIR: case VLNK:
+                       if (error = getinoquota(ip))
+                               return (error);
+               }
+       }
+#endif /* QUOTA */
+       /*
+        * If you're the super-user, you always get access.
+        */
+       if (cred->cr_uid == 0)
+               return (0);
+       /*
+        * Access check is based on only one of owner, group, public.
+        * If not owner, then check group. If not a member of the
+        * group, then check public access.
+        */
+       if (cred->cr_uid != ip->i_uid) {
+               mode >>= 3;
+               gp = cred->cr_groups;
+               for (i = 0; i < cred->cr_ngroups; i++, gp++)
+                       if (ip->i_gid == *gp)
+                               goto found;
+               mode >>= 3;
+found:
+               ;
+       }
+       if ((ip->i_mode & mode) != 0)
+               return (0);
+       return (EACCES);
+}
+
+/* ARGSUSED */
+ufs_getattr(vp, vap, cred, p)
+       struct vnode *vp;
+       register struct vattr *vap;
+       struct ucred *cred;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+
+       ITIMES(ip, &time, &time);
+       /*
+        * Copy from inode table
+        */
+       vap->va_fsid = ip->i_dev;
+       vap->va_fileid = ip->i_number;
+       vap->va_mode = ip->i_mode & ~IFMT;
+       vap->va_nlink = ip->i_nlink;
+       vap->va_uid = ip->i_uid;
+       vap->va_gid = ip->i_gid;
+       vap->va_rdev = (dev_t)ip->i_rdev;
+#ifdef tahoe
+       vap->va_size = ip->i_size;
+       vap->va_size_rsv = 0;
+#else
+       vap->va_qsize = ip->i_din.di_qsize;
+#endif
+       vap->va_atime.tv_sec = ip->i_atime;
+       vap->va_atime.tv_usec = 0;
+       vap->va_mtime.tv_sec = ip->i_mtime;
+       vap->va_mtime.tv_usec = 0;
+       vap->va_ctime.tv_sec = ip->i_ctime;
+       vap->va_ctime.tv_usec = 0;
+       vap->va_flags = ip->i_flags;
+       vap->va_gen = ip->i_gen;
+       /* this doesn't belong here */
+       if (vp->v_type == VBLK)
+               vap->va_blocksize = BLKDEV_IOSIZE;
+       else if (vp->v_type == VCHR)
+               vap->va_blocksize = MAXBSIZE;
+       else
+               vap->va_blocksize = ip->i_fs->fs_bsize;
+       vap->va_bytes = dbtob(ip->i_blocks);
+       vap->va_bytes_rsv = 0;
+       vap->va_type = vp->v_type;
+       return (0);
+}
+
+/*
+ * Set attribute vnode op. called from several syscalls
+ */
+ufs_setattr(vp, vap, cred, p)
+       register struct vnode *vp;
+       register struct vattr *vap;
+       register struct ucred *cred;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+       int error = 0;
+
+       /*
+        * Check for unsetable attributes.
+        */
+       if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+           (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+           (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+           ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
+               return (EINVAL);
+       }
+       /*
+        * Go through the fields and update iff not VNOVAL.
+        */
+       if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
+               if (error = chown1(vp, vap->va_uid, vap->va_gid, p))
+                       return (error);
+       if (vap->va_size != VNOVAL) {
+               if (vp->v_type == VDIR)
+                       return (EISDIR);
+               if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */
+                       return (error);
+       }
+       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+               if (cred->cr_uid != ip->i_uid &&
+                   (error = suser(cred, &p->p_acflag)))
+                       return (error);
+               if (vap->va_atime.tv_sec != VNOVAL)
+                       ip->i_flag |= IACC;
+               if (vap->va_mtime.tv_sec != VNOVAL)
+                       ip->i_flag |= IUPD;
+               ip->i_flag |= ICHG;
+               if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1))
+                       return (error);
+       }
+       if (vap->va_mode != (u_short)VNOVAL)
+               error = chmod1(vp, (int)vap->va_mode, p);
+       if (vap->va_flags != VNOVAL) {
+               if (cred->cr_uid != ip->i_uid &&
+                   (error = suser(cred, &p->p_acflag)))
+                       return (error);
+               if (cred->cr_uid == 0) {
+                       ip->i_flags = vap->va_flags;
+               } else {
+                       ip->i_flags &= 0xffff0000;
+                       ip->i_flags |= (vap->va_flags & 0xffff);
+               }
+               ip->i_flag |= ICHG;
+       }
+       return (error);
+}
+
+/*
+ * Change the mode on a file.
+ * Inode must be locked before calling.
+ */
+chmod1(vp, mode, p)
+       register struct vnode *vp;
+       register int mode;
+       struct proc *p;
+{
+       register struct ucred *cred = p->p_ucred;
+       register struct inode *ip = VTOI(vp);
+       int error;
+
+       if (cred->cr_uid != ip->i_uid &&
+           (error = suser(cred, &p->p_acflag)))
+               return (error);
+       if (cred->cr_uid) {
+               if (vp->v_type != VDIR && (mode & ISVTX))
+                       return (EFTYPE);
+               if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
+                       return (EPERM);
+       }
+       ip->i_mode &= ~07777;
+       ip->i_mode |= mode & 07777;
+       ip->i_flag |= ICHG;
+       if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
+               (void) vnode_pager_uncache(vp);
+       return (0);
+}
+
+/*
+ * Perform chown operation on inode ip;
+ * inode must be locked prior to call.
+ */
+chown1(vp, uid, gid, p)
+       register struct vnode *vp;
+       uid_t uid;
+       gid_t gid;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+       register struct ucred *cred = p->p_ucred;
+       uid_t ouid;
+       gid_t ogid;
+       int error = 0;
+#ifdef QUOTA
+       register int i;
+       long change;
+#endif
+
+       if (uid == (u_short)VNOVAL)
+               uid = ip->i_uid;
+       if (gid == (u_short)VNOVAL)
+               gid = ip->i_gid;
+       /*
+        * If we don't own the file, are trying to change the owner
+        * of the file, or are not a member of the target group,
+        * the caller must be superuser or the call fails.
+        */
+       if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
+           !groupmember((gid_t)gid, cred)) &&
+           (error = suser(cred, &p->p_acflag)))
+               return (error);
+       ouid = ip->i_uid;
+       ogid = ip->i_gid;
+#ifdef QUOTA
+       if (error = getinoquota(ip))
+               return (error);
+       if (ouid == uid) {
+               dqrele(vp, ip->i_dquot[USRQUOTA]);
+               ip->i_dquot[USRQUOTA] = NODQUOT;
+       }
+       if (ogid == gid) {
+               dqrele(vp, ip->i_dquot[GRPQUOTA]);
+               ip->i_dquot[GRPQUOTA] = NODQUOT;
+       }
+       change = ip->i_blocks;
+       (void) chkdq(ip, -change, cred, CHOWN);
+       (void) chkiq(ip, -1, cred, CHOWN);
+       for (i = 0; i < MAXQUOTAS; i++) {
+               dqrele(vp, ip->i_dquot[i]);
+               ip->i_dquot[i] = NODQUOT;
+       }
+#endif
+       ip->i_uid = uid;
+       ip->i_gid = gid;
+#ifdef QUOTA
+       if ((error = getinoquota(ip)) == 0) {
+               if (ouid == uid) {
+                       dqrele(vp, ip->i_dquot[USRQUOTA]);
+                       ip->i_dquot[USRQUOTA] = NODQUOT;
+               }
+               if (ogid == gid) {
+                       dqrele(vp, ip->i_dquot[GRPQUOTA]);
+                       ip->i_dquot[GRPQUOTA] = NODQUOT;
+               }
+               if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
+                       if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
+                               goto good;
+                       else
+                               (void) chkdq(ip, -change, cred, CHOWN|FORCE);
+               }
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       dqrele(vp, ip->i_dquot[i]);
+                       ip->i_dquot[i] = NODQUOT;
+               }
+       }
+       ip->i_uid = ouid;
+       ip->i_gid = ogid;
+       if (getinoquota(ip) == 0) {
+               if (ouid == uid) {
+                       dqrele(vp, ip->i_dquot[USRQUOTA]);
+                       ip->i_dquot[USRQUOTA] = NODQUOT;
+               }
+               if (ogid == gid) {
+                       dqrele(vp, ip->i_dquot[GRPQUOTA]);
+                       ip->i_dquot[GRPQUOTA] = NODQUOT;
+               }
+               (void) chkdq(ip, change, cred, FORCE|CHOWN);
+               (void) chkiq(ip, 1, cred, FORCE|CHOWN);
+               (void) getinoquota(ip);
+       }
+       return (error);
+good:
+       if (getinoquota(ip))
+               panic("chown: lost quota");
+#endif /* QUOTA */
+       if (ouid != uid || ogid != gid)
+               ip->i_flag |= ICHG;
+       if (ouid != uid && cred->cr_uid != 0)
+               ip->i_mode &= ~ISUID;
+       if (ogid != gid && cred->cr_uid != 0)
+               ip->i_mode &= ~ISGID;
+       return (0);
+}
+
+/*
+ * Vnode op for reading.
+ */
+/* ARGSUSED */
+ufs_read(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       register struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+       register struct inode *ip = VTOI(vp);
+       register struct fs *fs;
+       struct buf *bp;
+       daddr_t lbn, bn, rablock;
+       int size, diff, error = 0;
+       long n, on, type;
+
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_READ)
+               panic("ufs_read mode");
+       type = ip->i_mode & IFMT;
+       if (type != IFDIR && type != IFREG && type != IFLNK)
+               panic("ufs_read type");
+#endif
+       if (uio->uio_resid == 0)
+               return (0);
+       if (uio->uio_offset < 0)
+               return (EINVAL);
+       ip->i_flag |= IACC;
+       fs = ip->i_fs;
+       do {
+               lbn = lblkno(fs, uio->uio_offset);
+               on = blkoff(fs, uio->uio_offset);
+               n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
+               diff = ip->i_size - uio->uio_offset;
+               if (diff <= 0)
+                       return (0);
+               if (diff < n)
+                       n = diff;
+               size = blksize(fs, ip, lbn);
+               rablock = lbn + 1;
+               if (vp->v_lastr + 1 == lbn &&
+                   lblktosize(fs, rablock) < ip->i_size)
+                       error = breada(ITOV(ip), lbn, size, rablock,
+                               blksize(fs, ip, rablock), NOCRED, &bp);
+               else
+                       error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
+               vp->v_lastr = lbn;
+               n = MIN(n, size - bp->b_resid);
+               if (error) {
+                       brelse(bp);
+                       return (error);
+               }
+               error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
+               if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size)
+                       bp->b_flags |= B_AGE;
+               brelse(bp);
+       } while (error == 0 && uio->uio_resid > 0 && n != 0);
+       return (error);
+}
+
+/*
+ * Vnode op for writing.
+ */
+ufs_write(vp, uio, ioflag, cred)
+       register struct vnode *vp;
+       struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+       struct proc *p = uio->uio_procp;
+       register struct inode *ip = VTOI(vp);
+       register struct fs *fs;
+       struct buf *bp;
+       daddr_t lbn, bn;
+       u_long osize;
+       int n, on, flags;
+       int size, resid, error = 0;
+
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_WRITE)
+               panic("ufs_write mode");
+#endif
+       switch (vp->v_type) {
+       case VREG:
+               if (ioflag & IO_APPEND)
+                       uio->uio_offset = ip->i_size;
+               /* fall through */
+       case VLNK:
+               break;
+
+       case VDIR:
+               if ((ioflag & IO_SYNC) == 0)
+                       panic("ufs_write nonsync dir write");
+               break;
+
+       default:
+               panic("ufs_write type");
+       }
+       if (uio->uio_offset < 0)
+               return (EINVAL);
+       if (uio->uio_resid == 0)
+               return (0);
+       /*
+        * Maybe this should be above the vnode op call, but so long as
+        * file servers have no limits, i don't think it matters
+        */
+       if (vp->v_type == VREG && p &&
+           uio->uio_offset + uio->uio_resid >
+             p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+               psignal(p, SIGXFSZ);
+               return (EFBIG);
+       }
+       resid = uio->uio_resid;
+       osize = ip->i_size;
+       fs = ip->i_fs;
+       flags = 0;
+       if (ioflag & IO_SYNC)
+               flags = B_SYNC;
+       do {
+               lbn = lblkno(fs, uio->uio_offset);
+               on = blkoff(fs, uio->uio_offset);
+               n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
+               if (n < fs->fs_bsize)
+                       flags |= B_CLRBUF;
+               else
+                       flags &= ~B_CLRBUF;
+               if (error = balloc(ip, lbn, (int)(on + n), &bp, flags))
+                       break;
+               bn = bp->b_blkno;
+               if (uio->uio_offset + n > ip->i_size) {
+                       ip->i_size = uio->uio_offset + n;
+                       vnode_pager_setsize(vp, ip->i_size);
+               }
+               size = blksize(fs, ip, lbn);
+               (void) vnode_pager_uncache(vp);
+               n = MIN(n, size - bp->b_resid);
+               error = uiomove(bp->b_un.b_addr + on, n, uio);
+               if (ioflag & IO_SYNC)
+                       (void) bwrite(bp);
+               else if (n + on == fs->fs_bsize) {
+                       bp->b_flags |= B_AGE;
+                       bawrite(bp);
+               } else
+                       bdwrite(bp);
+               ip->i_flag |= IUPD|ICHG;
+               if (cred->cr_uid != 0)
+                       ip->i_mode &= ~(ISUID|ISGID);
+       } while (error == 0 && uio->uio_resid > 0 && n != 0);
+       if (error && (ioflag & IO_UNIT)) {
+               (void) itrunc(ip, osize, ioflag & IO_SYNC);
+               uio->uio_offset -= resid - uio->uio_resid;
+               uio->uio_resid = resid;
+       }
+       if (!error && (ioflag & IO_SYNC))
+               error = iupdat(ip, &time, &time, 1);
+       return (error);
+}
+
+/* ARGSUSED */
+ufs_ioctl(vp, com, data, fflag, cred, p)
+       struct vnode *vp;
+       int com;
+       caddr_t data;
+       int fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+
+       return (ENOTTY);
+}
+
+/* ARGSUSED */
+ufs_select(vp, which, fflags, cred, p)
+       struct vnode *vp;
+       int which, fflags;
+       struct ucred *cred;
+       struct proc *p;
+{
+
+       /*
+        * We should really check to see if I/O is possible.
+        */
+       return (1);
+}
+
+/*
+ * Mmap a file
+ *
+ * NB Currently unsupported.
+ */
+/* ARGSUSED */
+ufs_mmap(vp, fflags, cred, p)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
+       struct proc *p;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Synch an open file.
+ */
+/* ARGSUSED */
+ufs_fsync(vp, fflags, cred, waitfor, p)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
+       int waitfor;
+       struct proc *p;
+{
+       struct inode *ip = VTOI(vp);
+
+       if (fflags & FWRITE)
+               ip->i_flag |= ICHG;
+       vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
+       return (iupdat(ip, &time, &time, waitfor == MNT_WAIT));
+}
+
+/*
+ * Seek on a file
+ *
+ * Nothing to do, so just return.
+ */
+/* ARGSUSED */
+ufs_seek(vp, oldoff, newoff, cred)
+       struct vnode *vp;
+       off_t oldoff, newoff;
+       struct ucred *cred;
+{
+
+       return (0);
+}
+
+/*
+ * ufs remove
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+ufs_remove(ndp, p)
+       struct nameidata *ndp;
+       struct proc *p;
+{
+       register struct inode *ip, *dp;
+       int error;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
+       error = dirremove(ndp);
+       if (!error) {
+               ip->i_nlink--;
+               ip->i_flag |= ICHG;
+       }
+       if (dp == ip)
+               vrele(ITOV(ip));
+       else
+               iput(ip);
+       iput(dp);
+       return (error);
+}
+
+/*
+ * link vnode call
+ */
+ufs_link(vp, ndp, p)
+       register struct vnode *vp;
+       register struct nameidata *ndp;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+       int error;
+
+#ifdef DIANOSTIC
+       if ((ndp->ni_nameiop & HASBUF) == 0)
+               panic("ufs_link: no name");
+#endif
+       if ((unsigned short)ip->i_nlink >= LINK_MAX) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               return (EMLINK);
+       }
+       if (ndp->ni_dvp != vp)
+               ILOCK(ip);
+       ip->i_nlink++;
+       ip->i_flag |= ICHG;
+       error = iupdat(ip, &time, &time, 1);
+       if (!error)
+               error = direnter(ip, ndp);
+       if (ndp->ni_dvp != vp)
+               IUNLOCK(ip);
+       FREE(ndp->ni_pnbuf, M_NAMEI);
+       vput(ndp->ni_dvp);
+       if (error) {
+               ip->i_nlink--;
+               ip->i_flag |= ICHG;
+       }
+       return (error);
+}
+
+/*
+ * Rename system call.
+ *     rename("foo", "bar");
+ * is essentially
+ *     unlink("bar");
+ *     link("foo", "bar");
+ *     unlink("foo");
+ * but ``atomically''.  Can't do full commit without saving state in the
+ * inode on disk which isn't feasible at this time.  Best we can do is
+ * always guarantee the target exists.
+ *
+ * Basic algorithm is:
+ *
+ * 1) Bump link count on source while we're linking it to the
+ *    target.  This also ensure the inode won't be deleted out
+ *    from underneath us while we work (it may be truncated by
+ *    a concurrent `trunc' or `open' for creation).
+ * 2) Link source to destination.  If destination already exists,
+ *    delete it first.
+ * 3) Unlink source reference to inode if still around. If a
+ *    directory was moved and the parent of the destination
+ *    is different from the source, patch the ".." entry in the
+ *    directory.
+ */
+ufs_rename(fndp, tndp, p)
+       register struct nameidata *fndp, *tndp;
+       struct proc *p;
+{
+       register struct inode *ip, *xp, *dp;
+       struct dirtemplate dirbuf;
+       int doingdirectory = 0, oldparent = 0, newparent = 0;
+       int error = 0;
+
+#ifdef DIANOSTIC
+       if ((tndp->ni_nameiop & HASBUF) == 0 ||
+           (fndp->ni_nameiop & HASBUF) == 0)
+               panic("ufs_rename: no name");
+#endif
+       dp = VTOI(fndp->ni_dvp);
+       ip = VTOI(fndp->ni_vp);
+       /*
+        * Check if just deleting a link name.
+        */
+       if (fndp->ni_vp == tndp->ni_vp) {
+               VOP_ABORTOP(tndp);
+               vput(tndp->ni_dvp);
+               vput(tndp->ni_vp);
+               vrele(fndp->ni_dvp);
+               if ((ip->i_mode&IFMT) == IFDIR) {
+                       VOP_ABORTOP(fndp);
+                       vrele(fndp->ni_vp);
+                       return (EINVAL);
+               }
+               doingdirectory = 0;
+               goto unlinkit;
+       }
+       ILOCK(ip);
+       if ((ip->i_mode&IFMT) == IFDIR) {
+               /*
+                * Avoid ".", "..", and aliases of "." for obvious reasons.
+                */
+               if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') ||
+                   dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) {
+                       VOP_ABORTOP(tndp);
+                       vput(tndp->ni_dvp);
+                       if (tndp->ni_vp)
+                               vput(tndp->ni_vp);
+                       VOP_ABORTOP(fndp);
+                       vrele(fndp->ni_dvp);
+                       vput(fndp->ni_vp);
+                       return (EINVAL);
+               }
+               ip->i_flag |= IRENAME;
+               oldparent = dp->i_number;
+               doingdirectory++;
+       }
+       vrele(fndp->ni_dvp);
+
+       /*
+        * 1) Bump link count while we're moving stuff
+        *    around.  If we crash somewhere before
+        *    completing our work, the link count
+        *    may be wrong, but correctable.
+        */
+       ip->i_nlink++;
+       ip->i_flag |= ICHG;
+       error = iupdat(ip, &time, &time, 1);
+       IUNLOCK(ip);
+
+       /*
+        * When the target exists, both the directory
+        * and target vnodes are returned locked.
+        */
+       dp = VTOI(tndp->ni_dvp);
+       xp = NULL;
+       if (tndp->ni_vp)
+               xp = VTOI(tndp->ni_vp);
+       /*
+        * If ".." must be changed (ie the directory gets a new
+        * parent) then the source directory must not be in the
+        * directory heirarchy above the target, as this would
+        * orphan everything below the source directory. Also
+        * the user must have write permission in the source so
+        * as to be able to change "..". We must repeat the call 
+        * to namei, as the parent directory is unlocked by the
+        * call to checkpath().
+        */
+       if (oldparent != dp->i_number)
+               newparent = dp->i_number;
+       if (doingdirectory && newparent) {
+               VOP_LOCK(fndp->ni_vp);
+               error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p);
+               VOP_UNLOCK(fndp->ni_vp);
+               if (error)
+                       goto bad;
+               if (xp != NULL)
+                       iput(xp);
+               if (error = checkpath(ip, dp, tndp->ni_cred))
+                       goto out;
+               if ((tndp->ni_nameiop & SAVESTART) == 0)
+                       panic("ufs_rename: lost to startdir");
+               if (error = lookup(tndp, p))
+                       goto out;
+               dp = VTOI(tndp->ni_dvp);
+               xp = NULL;
+               if (tndp->ni_vp)
+                       xp = VTOI(tndp->ni_vp);
+       }
+       /*
+        * 2) If target doesn't exist, link the target
+        *    to the source and unlink the source. 
+        *    Otherwise, rewrite the target directory
+        *    entry to reference the source inode and
+        *    expunge the original entry's existence.
+        */
+       if (xp == NULL) {
+               if (dp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
+               /*
+                * Account for ".." in new directory.
+                * When source and destination have the same
+                * parent we don't fool with the link count.
+                */
+               if (doingdirectory && newparent) {
+                       if ((unsigned short)dp->i_nlink >= LINK_MAX) {
+                               error = EMLINK;
+                               goto bad;
+                       }
+                       dp->i_nlink++;
+                       dp->i_flag |= ICHG;
+                       if (error = iupdat(dp, &time, &time, 1))
+                               goto bad;
+               }
+               if (error = direnter(ip, tndp)) {
+                       if (doingdirectory && newparent) {
+                               dp->i_nlink--;
+                               dp->i_flag |= ICHG;
+                               (void) iupdat(dp, &time, &time, 1);
+                       }
+                       goto bad;
+               }
+               iput(dp);
+       } else {
+               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
+               /*
+                * Short circuit rename(foo, foo).
+                */
+               if (xp->i_number == ip->i_number)
+                       panic("rename: same file");
+               /*
+                * If the parent directory is "sticky", then the user must
+                * own the parent directory, or the destination of the rename,
+                * otherwise the destination may not be changed (except by
+                * root). This implements append-only directories.
+                */
+               if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
+                   tndp->ni_cred->cr_uid != dp->i_uid &&
+                   xp->i_uid != tndp->ni_cred->cr_uid) {
+                       error = EPERM;
+                       goto bad;
+               }
+               /*
+                * Target must be empty if a directory and have no links
+                * to it. Also, ensure source and target are compatible
+                * (both directories, or both not directories).
+                */
+               if ((xp->i_mode&IFMT) == IFDIR) {
+                       if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 
+                           xp->i_nlink > 2) {
+                               error = ENOTEMPTY;
+                               goto bad;
+                       }
+                       if (!doingdirectory) {
+                               error = ENOTDIR;
+                               goto bad;
+                       }
+                       cache_purge(ITOV(dp));
+               } else if (doingdirectory) {
+                       error = EISDIR;
+                       goto bad;
+               }
+               if (error = dirrewrite(dp, ip, tndp))
+                       goto bad;
+               /*
+                * If the target directory is in the same
+                * directory as the source directory,
+                * decrement the link count on the parent
+                * of the target directory.
+                */
+                if (doingdirectory && !newparent) {
+                       dp->i_nlink--;
+                       dp->i_flag |= ICHG;
+               }
+               vput(ITOV(dp));
+               /*
+                * Adjust the link count of the target to
+                * reflect the dirrewrite above.  If this is
+                * a directory it is empty and there are
+                * no links to it, so we can squash the inode and
+                * any space associated with it.  We disallowed
+                * renaming over top of a directory with links to
+                * it above, as the remaining link would point to
+                * a directory without "." or ".." entries.
+                */
+               xp->i_nlink--;
+               if (doingdirectory) {
+                       if (--xp->i_nlink != 0)
+                               panic("rename: linked directory");
+                       error = itrunc(xp, (u_long)0, IO_SYNC);
+               }
+               xp->i_flag |= ICHG;
+               iput(xp);
+               xp = NULL;
+       }
+
+       /*
+        * 3) Unlink the source.
+        */
+unlinkit:
+       fndp->ni_nameiop &= ~MODMASK;
+       fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF;
+       if ((fndp->ni_nameiop & SAVESTART) == 0)
+               panic("ufs_rename: lost from startdir");
+       (void) lookup(fndp, p);
+       if (fndp->ni_vp != NULL) {
+               xp = VTOI(fndp->ni_vp);
+               dp = VTOI(fndp->ni_dvp);
+       } else {
+               /*
+                * From name has disappeared.
+                */
+               if (doingdirectory)
+                       panic("rename: lost dir entry");
+               vrele(ITOV(ip));
+               return (0);
+       }
+       /*
+        * Ensure that the directory entry still exists and has not
+        * changed while the new name has been entered. If the source is
+        * a file then the entry may have been unlinked or renamed. In
+        * either case there is no further work to be done. If the source
+        * is a directory then it cannot have been rmdir'ed; its link
+        * count of three would cause a rmdir to fail with ENOTEMPTY.
+        * The IRENAME flag ensures that it cannot be moved by another
+        * rename.
+        */
+       if (xp != ip) {
+               if (doingdirectory)
+                       panic("rename: lost dir entry");
+       } else {
+               /*
+                * If the source is a directory with a
+                * new parent, the link count of the old
+                * parent directory must be decremented
+                * and ".." set to point to the new parent.
+                */
+               if (doingdirectory && newparent) {
+                       dp->i_nlink--;
+                       dp->i_flag |= ICHG;
+                       error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf,
+                               sizeof (struct dirtemplate), (off_t)0,
+                               UIO_SYSSPACE, IO_NODELOCKED, 
+                               tndp->ni_cred, (int *)0, (struct proc *)0);
+                       if (error == 0) {
+                               if (dirbuf.dotdot_namlen != 2 ||
+                                   dirbuf.dotdot_name[0] != '.' ||
+                                   dirbuf.dotdot_name[1] != '.') {
+                                       dirbad(xp, 12, "rename: mangled dir");
+                               } else {
+                                       dirbuf.dotdot_ino = newparent;
+                                       (void) vn_rdwr(UIO_WRITE, ITOV(xp),
+                                           (caddr_t)&dirbuf,
+                                           sizeof (struct dirtemplate),
+                                           (off_t)0, UIO_SYSSPACE,
+                                           IO_NODELOCKED|IO_SYNC,
+                                           tndp->ni_cred, (int *)0,
+                                           (struct proc *)0);
+                                       cache_purge(ITOV(dp));
+                               }
+                       }
+               }
+               error = dirremove(fndp);
+               if (!error) {
+                       xp->i_nlink--;
+                       xp->i_flag |= ICHG;
+               }
+               xp->i_flag &= ~IRENAME;
+       }
+       if (dp)
+               vput(ITOV(dp));
+       if (xp)
+               vput(ITOV(xp));
+       vrele(ITOV(ip));
+       return (error);
+
+bad:
+       if (xp)
+               vput(ITOV(xp));
+       vput(ITOV(dp));
+out:
+       ip->i_nlink--;
+       ip->i_flag |= ICHG;
+       vrele(ITOV(ip));
+       return (error);
+}
+
+/*
+ * A virgin directory (no blushing please).
+ */
+struct dirtemplate mastertemplate = {
+       0, 12, 1, ".",
+       0, DIRBLKSIZ - 12, 2, ".."
+};
+
+/*
+ * Mkdir system call
+ */
+ufs_mkdir(ndp, vap, p)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       struct proc *p;
+{
+       register struct inode *ip, *dp;
+       struct inode *tip;
+       struct vnode *dvp;
+       struct dirtemplate dirtemplate;
+       int error;
+       int dmode;
+
+#ifdef DIANOSTIC
+       if ((ndp->ni_nameiop & HASBUF) == 0)
+               panic("ufs_mkdir: no name");
+#endif
+       dvp = ndp->ni_dvp;
+       dp = VTOI(dvp);
+       if ((unsigned short)dp->i_nlink >= LINK_MAX) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               iput(dp);
+               return (EMLINK);
+       }
+       dmode = vap->va_mode&0777;
+       dmode |= IFDIR;
+       /*
+        * Must simulate part of maknode here to acquire the inode, but
+        * not have it entered in the parent directory. The entry is made
+        * later after writing "." and ".." entries.
+        */
+       if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               iput(dp);
+               return (error);
+       }
+       ip = tip;
+       ip->i_uid = ndp->ni_cred->cr_uid;
+       ip->i_gid = dp->i_gid;
+#ifdef QUOTA
+       if ((error = getinoquota(ip)) ||
+           (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               ifree(ip, ip->i_number, dmode);
+               iput(ip);
+               iput(dp);
+               return (error);
+       }
+#endif
+       ip->i_flag |= IACC|IUPD|ICHG;
+       ip->i_mode = dmode;
+       ITOV(ip)->v_type = VDIR;        /* Rest init'd in iget() */
+       ip->i_nlink = 2;
+       error = iupdat(ip, &time, &time, 1);
+
+       /*
+        * Bump link count in parent directory
+        * to reflect work done below.  Should
+        * be done before reference is created
+        * so reparation is possible if we crash.
+        */
+       dp->i_nlink++;
+       dp->i_flag |= ICHG;
+       if (error = iupdat(dp, &time, &time, 1))
+               goto bad;
+
+       /*
+        * Initialize directory with "."
+        * and ".." from static template.
+        */
+       dirtemplate = mastertemplate;
+       dirtemplate.dot_ino = ip->i_number;
+       dirtemplate.dotdot_ino = dp->i_number;
+       error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate,
+           sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
+           IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0);
+       if (error) {
+               dp->i_nlink--;
+               dp->i_flag |= ICHG;
+               goto bad;
+       }
+       if (DIRBLKSIZ > dp->i_fs->fs_fsize) {
+               panic("mkdir: blksize");     /* XXX - should grow w/balloc() */
+       } else {
+               ip->i_size = DIRBLKSIZ;
+               ip->i_flag |= ICHG;
+       }
+       /*
+        * Directory all set up, now
+        * install the entry for it in
+        * the parent directory.
+        */
+       if (error = direnter(ip, ndp)) {
+               dp->i_nlink--;
+               dp->i_flag |= ICHG;
+       }
+bad:
+       /*
+        * No need to do an explicit itrunc here,
+        * vrele will do this for us because we set
+        * the link count to 0.
+        */
+       if (error) {
+               ip->i_nlink = 0;
+               ip->i_flag |= ICHG;
+               iput(ip);
+       } else
+               ndp->ni_vp = ITOV(ip);
+       FREE(ndp->ni_pnbuf, M_NAMEI);
+       iput(dp);
+       return (error);
+}
+
+/*
+ * Rmdir system call.
+ */
+ufs_rmdir(ndp, p)
+       register struct nameidata *ndp;
+       struct proc *p;
+{
+       register struct inode *ip, *dp;
+       int error = 0;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
+       /*
+        * No rmdir "." please.
+        */
+       if (dp == ip) {
+               vrele(ITOV(dp));
+               iput(ip);
+               return (EINVAL);
+       }
+       /*
+        * Verify the directory is empty (and valid).
+        * (Rmdir ".." won't be valid since
+        *  ".." will contain a reference to
+        *  the current directory and thus be
+        *  non-empty.)
+        */
+       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) {
+               error = ENOTEMPTY;
+               goto out;
+       }
+       /*
+        * Delete reference to directory before purging
+        * inode.  If we crash in between, the directory
+        * will be reattached to lost+found,
+        */
+       if (error = dirremove(ndp))
+               goto out;
+       dp->i_nlink--;
+       dp->i_flag |= ICHG;
+       cache_purge(ITOV(dp));
+       iput(dp);
+       ndp->ni_dvp = NULL;
+       /*
+        * Truncate inode.  The only stuff left
+        * in the directory is "." and "..".  The
+        * "." reference is inconsequential since
+        * we're quashing it.  The ".." reference
+        * has already been adjusted above.  We've
+        * removed the "." reference and the reference
+        * in the parent directory, but there may be
+        * other hard links so decrement by 2 and
+        * worry about them later.
+        */
+       ip->i_nlink -= 2;
+       error = itrunc(ip, (u_long)0, IO_SYNC);
+       cache_purge(ITOV(ip));
+out:
+       if (ndp->ni_dvp)
+               iput(dp);
+       iput(ip);
+       return (error);
+}
+
+/*
+ * symlink -- make a symbolic link
+ */
+ufs_symlink(ndp, vap, target, p)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       char *target;
+       struct proc *p;
+{
+       struct inode *ip;
+       int error;
+
+       error = maknode(IFLNK | vap->va_mode, ndp, &ip);
+       if (error)
+               return (error);
+       error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0,
+               UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0,
+               (struct proc *)0);
+       iput(ip);
+       return (error);
+}
+
+/*
+ * Vnode op for read and write
+ */
+ufs_readdir(vp, uio, cred, eofflagp)
+       struct vnode *vp;
+       register struct uio *uio;
+       struct ucred *cred;
+       int *eofflagp;
+{
+       int count, lost, error;
+
+       count = uio->uio_resid;
+       count &= ~(DIRBLKSIZ - 1);
+       lost = uio->uio_resid - count;
+       if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
+               return (EINVAL);
+       uio->uio_resid = count;
+       uio->uio_iov->iov_len = count;
+       error = ufs_read(vp, uio, 0, cred);
+       uio->uio_resid += lost;
+       if ((VTOI(vp)->i_size - uio->uio_offset) <= 0)
+               *eofflagp = 1;
+       else
+               *eofflagp = 0;
+       return (error);
+}
+
+/*
+ * Return target name of a symbolic link
+ */
+ufs_readlink(vp, uiop, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       struct ucred *cred;
+{
+
+       return (ufs_read(vp, uiop, 0, cred));
+}
+
+/*
+ * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. If a buffer has been saved in anticipation of a CREATE, delete it.
+ */
+/* ARGSUSED */
+ufs_abortop(ndp)
+       struct nameidata *ndp;
+{
+
+       if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
+               FREE(ndp->ni_pnbuf, M_NAMEI);
+       return (0);
+}
+
+/*
+ * Lock an inode.
+ */
+ufs_lock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       ILOCK(ip);
+       return (0);
+}
+
+/*
+ * Unlock an inode.
+ */
+ufs_unlock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (!(ip->i_flag & ILOCKED))
+               panic("ufs_unlock NOT LOCKED");
+       IUNLOCK(ip);
+       return (0);
+}
+
+/*
+ * Check for a locked inode.
+ */
+ufs_islocked(vp)
+       struct vnode *vp;
+{
+
+       if (VTOI(vp)->i_flag & ILOCKED)
+               return (1);
+       return (0);
+}
+
+/*
+ * Get access to bmap
+ */
+ufs_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+       struct inode *ip = VTOI(vp);
+
+       if (vpp != NULL)
+               *vpp = ip->i_devvp;
+       if (bnp == NULL)
+               return (0);
+       return (bmap(ip, bn, bnp));
+}
+
+/*
+ * Calculate the logical to physical mapping if not done already,
+ * then call the device strategy routine.
+ */
+int checkoverlap = 0;
+
+ufs_strategy(bp)
+       register struct buf *bp;
+{
+       register struct inode *ip = VTOI(bp->b_vp);
+       struct vnode *vp;
+       int error;
+
+       if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
+               panic("ufs_strategy: spec");
+       if (bp->b_blkno == bp->b_lblkno) {
+               if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno))
+                       return (error);
+               if ((long)bp->b_blkno == -1)
+                       clrbuf(bp);
+       }
+       if ((long)bp->b_blkno == -1) {
+               biodone(bp);
+               return (0);
+       }
+#ifdef DIAGNOSTIC
+       if (checkoverlap) {
+               register struct buf *ep;
+               struct buf *ebp;
+               daddr_t start, last;
+
+               ebp = &buf[nbuf];
+               start = bp->b_blkno;
+               last = start + btodb(bp->b_bcount) - 1;
+               for (ep = buf; ep < ebp; ep++) {
+                       if (ep == bp || (ep->b_flags & B_INVAL) ||
+                           ep->b_vp == NULLVP)
+                               continue;
+                       if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0))
+                               continue;
+                       if (vp != ip->i_devvp)
+                               continue;
+                       /* look for overlap */
+                       if (ep->b_bcount == 0 || ep->b_blkno > last ||
+                           ep->b_blkno + btodb(ep->b_bcount) <= start)
+                               continue;
+                       vprint("Disk overlap", vp);
+                       printf("\tstart %d, end %d overlap start %d, end %d\n",
+                               start, last, ep->b_blkno,
+                               ep->b_blkno + btodb(ep->b_bcount) - 1);
+                       panic("Disk buffer overlap");
+               }
+       }
+#endif /* DIAGNOSTIC */
+       vp = ip->i_devvp;
+       bp->b_dev = vp->v_rdev;
+       (*(vp->v_op->vop_strategy))(bp);
+       return (0);
+}
+
+/*
+ * Print out the contents of an inode.
+ */
+ufs_print(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
+               major(ip->i_dev), minor(ip->i_dev));
+#ifdef FIFO
+       if (vp->v_type == VFIFO)
+               fifo_printinfo(vp);
+#endif /* FIFO */
+       printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
+       if (ip->i_spare0 == 0)
+               return;
+       printf("\towner pid %d", ip->i_spare0);
+       if (ip->i_spare1)
+               printf(" waiting pid %d", ip->i_spare1);
+       printf("\n");
+}
+
+/*
+ * Read wrapper for special devices.
+ */
+ufsspec_read(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+
+       /*
+        * Set access flag.
+        */
+       VTOI(vp)->i_flag |= IACC;
+       return (spec_read(vp, uio, ioflag, cred));
+}
+
+/*
+ * Write wrapper for special devices.
+ */
+ufsspec_write(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+
+       /*
+        * Set update and change flags.
+        */
+       VTOI(vp)->i_flag |= IUPD|ICHG;
+       return (spec_write(vp, uio, ioflag, cred));
+}
+
+/*
+ * Close wrapper for special devices.
+ *
+ * Update the times on the inode then do device close.
+ */
+ufsspec_close(vp, fflag, cred, p)
+       struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+               ITIMES(ip, &time, &time);
+       return (spec_close(vp, fflag, cred, p));
+}
+
+#ifdef FIFO
+/*
+ * Read wrapper for fifo's
+ */
+ufsfifo_read(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+
+       /*
+        * Set access flag.
+        */
+       VTOI(vp)->i_flag |= IACC;
+       return (fifo_read(vp, uio, ioflag, cred));
+}
+
+/*
+ * Write wrapper for fifo's.
+ */
+ufsfifo_write(vp, uio, ioflag, cred)
+       struct vnode *vp;
+       struct uio *uio;
+       int ioflag;
+       struct ucred *cred;
+{
+
+       /*
+        * Set update and change flags.
+        */
+       VTOI(vp)->i_flag |= IUPD|ICHG;
+       return (fifo_write(vp, uio, ioflag, cred));
+}
+
+/*
+ * Close wrapper for fifo's.
+ *
+ * Update the times on the inode then do device close.
+ */
+ufsfifo_close(vp, fflag, cred, p)
+       struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
+       struct proc *p;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+               ITIMES(ip, &time, &time);
+       return (fifo_close(vp, fflag, cred, p));
+}
+#endif /* FIFO */
+
+/*
+ * Allocate a new inode.
+ */
+maknode(mode, ndp, ipp)
+       int mode;
+       register struct nameidata *ndp;
+       struct inode **ipp;
+{
+       register struct inode *ip;
+       struct inode *tip;
+       register struct inode *pdir = VTOI(ndp->ni_dvp);
+       ino_t ipref;
+       int error;
+
+#ifdef DIANOSTIC
+       if ((ndp->ni_nameiop & HASBUF) == 0)
+               panic("maknode: no name");
+#endif
+       *ipp = 0;
+       if ((mode & IFMT) == 0)
+               mode |= IFREG;
+       if ((mode & IFMT) == IFDIR)
+               ipref = dirpref(pdir->i_fs);
+       else
+               ipref = pdir->i_number;
+       if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               iput(pdir);
+               return (error);
+       }
+       ip = tip;
+       ip->i_uid = ndp->ni_cred->cr_uid;
+       ip->i_gid = pdir->i_gid;
+#ifdef QUOTA
+       if ((error = getinoquota(ip)) ||
+           (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
+               free(ndp->ni_pnbuf, M_NAMEI);
+               ifree(ip, ip->i_number, mode);
+               iput(ip);
+               iput(pdir);
+               return (error);
+       }
+#endif
+       ip->i_flag |= IACC|IUPD|ICHG;
+       ip->i_mode = mode;
+       ITOV(ip)->v_type = IFTOVT(mode);        /* Rest init'd in iget() */
+       ip->i_nlink = 1;
+       if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
+           suser(ndp->ni_cred, NULL))
+               ip->i_mode &= ~ISGID;
+
+       /*
+        * Make sure inode goes to disk before directory entry.
+        */
+       if (error = iupdat(ip, &time, &time, 1))
+               goto bad;
+       if (error = direnter(ip, ndp))
+               goto bad;
+       if ((ndp->ni_nameiop & SAVESTART) == 0)
+               FREE(ndp->ni_pnbuf, M_NAMEI);
+       iput(pdir);
+       *ipp = ip;
+       return (0);
+
+bad:
+       /*
+        * Write error occurred trying to update the inode
+        * or the directory so must deallocate the inode.
+        */
+       free(ndp->ni_pnbuf, M_NAMEI);
+       iput(pdir);
+       ip->i_nlink = 0;
+       ip->i_flag |= ICHG;
+       iput(ip);
+       return (error);
+}
+
+/*
+ * Advisory record locking support
+ */
+ufs_advlock(vp, id, op, fl, flags)
+       struct vnode *vp;
+       caddr_t id;
+       int op;
+       register struct flock *fl;
+       int flags;
+{
+       register struct inode *ip = VTOI(vp);
+       register struct lockf *lock;
+       off_t start, end;
+       int error;
+
+       /*
+        * Avoid the common case of unlocking when inode has no locks.
+        */
+       if (ip->i_lockf == (struct lockf *)0) {
+               if (op != F_SETLK) {
+                       fl->l_type = F_UNLCK;
+                       return (0);
+               }
+       }
+       /*
+        * Convert the flock structure into a start and end.
+        */
+       switch (fl->l_whence) {
+
+       case SEEK_SET:
+       case SEEK_CUR:
+               /*
+                * Caller is responsible for adding any necessary offset
+                * when SEEK_CUR is used.
+                */
+               start = fl->l_start;
+               break;
+
+       case SEEK_END:
+               start = ip->i_size + fl->l_start;
+               break;
+
+       default:
+               return (EINVAL);
+       }
+       if (start < 0)
+               return (EINVAL);
+       if (fl->l_len == 0)
+               end = -1;
+       else
+               end = start + fl->l_len - 1;
+       /*
+        * Create the lockf structure
+        */
+       MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
+       lock->lf_start = start;
+       lock->lf_end = end;
+       lock->lf_id = id;
+       lock->lf_inode = ip;
+       lock->lf_type = fl->l_type;
+       lock->lf_next = (struct lockf *)0;
+       lock->lf_block = (struct lockf *)0;
+       lock->lf_flags = flags;
+       /*
+        * Do the requested operation.
+        */
+       switch(op) {
+       case F_SETLK:
+               return (lf_setlock(lock));
+
+       case F_UNLCK:
+               error = lf_clearlock(lock);
+               FREE(lock, M_LOCKF);
+               return (error);
+
+       case F_GETLK:
+               error = lf_getlock(lock, fl);
+               FREE(lock, M_LOCKF);
+               return (error);
+       
+       default:
+               free(lock, M_LOCKF);
+               return (EINVAL);
+       }
+       /* NOTREACHED */
+}
+
+/*
+ * Global vfs data structures for ufs
+ */
+struct vnodeops ufs_vnodeops = {
+       ufs_lookup,             /* lookup */
+       ufs_create,             /* create */
+       ufs_mknod,              /* mknod */
+       ufs_open,               /* open */
+       ufs_close,              /* close */
+       ufs_access,             /* access */
+       ufs_getattr,            /* getattr */
+       ufs_setattr,            /* setattr */
+       ufs_read,               /* read */
+       ufs_write,              /* write */
+       ufs_ioctl,              /* ioctl */
+       ufs_select,             /* select */
+       ufs_mmap,               /* mmap */
+       ufs_fsync,              /* fsync */
+       ufs_seek,               /* seek */
+       ufs_remove,             /* remove */
+       ufs_link,               /* link */
+       ufs_rename,             /* rename */
+       ufs_mkdir,              /* mkdir */
+       ufs_rmdir,              /* rmdir */
+       ufs_symlink,            /* symlink */
+       ufs_readdir,            /* readdir */
+       ufs_readlink,           /* readlink */
+       ufs_abortop,            /* abortop */
+       ufs_inactive,           /* inactive */
+       ufs_reclaim,            /* reclaim */
+       ufs_lock,               /* lock */
+       ufs_unlock,             /* unlock */
+       ufs_bmap,               /* bmap */
+       ufs_strategy,           /* strategy */
+       ufs_print,              /* print */
+       ufs_islocked,           /* islocked */
+       ufs_advlock,            /* advlock */
+};
+
+struct vnodeops spec_inodeops = {
+       spec_lookup,            /* lookup */
+       spec_create,            /* create */
+       spec_mknod,             /* mknod */
+       spec_open,              /* open */
+       ufsspec_close,          /* close */
+       ufs_access,             /* access */
+       ufs_getattr,            /* getattr */
+       ufs_setattr,            /* setattr */
+       ufsspec_read,           /* read */
+       ufsspec_write,          /* write */
+       spec_ioctl,             /* ioctl */
+       spec_select,            /* select */
+       spec_mmap,              /* mmap */
+       spec_fsync,             /* fsync */
+       spec_seek,              /* seek */
+       spec_remove,            /* remove */
+       spec_link,              /* link */
+       spec_rename,            /* rename */
+       spec_mkdir,             /* mkdir */
+       spec_rmdir,             /* rmdir */
+       spec_symlink,           /* symlink */
+       spec_readdir,           /* readdir */
+       spec_readlink,          /* readlink */
+       spec_abortop,           /* abortop */
+       ufs_inactive,           /* inactive */
+       ufs_reclaim,            /* reclaim */
+       ufs_lock,               /* lock */
+       ufs_unlock,             /* unlock */
+       spec_bmap,              /* bmap */
+       spec_strategy,          /* strategy */
+       ufs_print,              /* print */
+       ufs_islocked,           /* islocked */
+       spec_advlock,           /* advlock */
+};
+
+#ifdef FIFO
+struct vnodeops fifo_inodeops = {
+       fifo_lookup,            /* lookup */
+       fifo_create,            /* create */
+       fifo_mknod,             /* mknod */
+       fifo_open,              /* open */
+       ufsfifo_close,          /* close */
+       ufs_access,             /* access */
+       ufs_getattr,            /* getattr */
+       ufs_setattr,            /* setattr */
+       ufsfifo_read,           /* read */
+       ufsfifo_write,          /* write */
+       fifo_ioctl,             /* ioctl */
+       fifo_select,            /* select */
+       fifo_mmap,              /* mmap */
+       fifo_fsync,             /* fsync */
+       fifo_seek,              /* seek */
+       fifo_remove,            /* remove */
+       fifo_link,              /* link */
+       fifo_rename,            /* rename */
+       fifo_mkdir,             /* mkdir */
+       fifo_rmdir,             /* rmdir */
+       fifo_symlink,           /* symlink */
+       fifo_readdir,           /* readdir */
+       fifo_readlink,          /* readlink */
+       fifo_abortop,           /* abortop */
+       ufs_inactive,           /* inactive */
+       ufs_reclaim,            /* reclaim */
+       ufs_lock,               /* lock */
+       ufs_unlock,             /* unlock */
+       fifo_bmap,              /* bmap */
+       fifo_strategy,          /* strategy */
+       ufs_print,              /* print */
+       ufs_islocked,           /* islocked */
+       fifo_advlock,           /* advlock */
+};
+#endif /* FIFO */
+
+enum vtype iftovt_tab[16] = {
+       VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
+       VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
+};
+int    vttoif_tab[9] = {
+       0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT,
+};
diff --git a/usr/src/sys.386bsd/ufs/ufsmount.h b/usr/src/sys.386bsd/ufs/ufsmount.h
new file mode 100644 (file)
index 0000000..262665d
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufsmount.h  7.9 (Berkeley) 5/8/91
+ */
+
+/*
+ * This structure describes the UFS specific mount structure data.
+ */
+struct ufsmount {
+       struct  mount *um_mountp;       /* vfs structure for this filesystem */
+       dev_t   um_dev;                 /* device mounted */
+       struct  vnode *um_devvp;        /* vnode for block device mounted */
+       struct  fs *um_fs;              /* pointer to superblock */
+       struct  vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */
+       struct  ucred *um_cred[MAXQUOTAS]; /* cred for access to quota file */
+       time_t  um_btime[MAXQUOTAS];    /* block quota time limit */
+       time_t  um_itime[MAXQUOTAS];    /* inode quota time limit */
+       char    um_qflags[MAXQUOTAS];   /* quota specific flags, see below */
+};
+/*
+ * Flags describing the state of quotas.
+ */
+#define        QTF_OPENING     0x01            /* Q_QUOTAON in progress */
+#define        QTF_CLOSING     0x02            /* Q_QUOTAOFF in progress */
+
+#ifdef KERNEL
+/*
+ * Convert mount ptr to ufsmount ptr.
+ */
+#define VFSTOUFS(mp)   ((struct ufsmount *)((mp)->mnt_data))
+#endif /* KERNEL */
+
+/*
+ * Prototypes for UFS mount operations
+ */
+int ufs_mount __P((struct mount *mp, char *path, caddr_t data,
+       struct nameidata *ndp, struct proc *p));
+int ufs_start __P((struct mount *mp, int flags, struct proc *p));
+int ufs_unmount __P((struct mount *mp, int mntflags, struct proc *p));
+int ufs_root __P((struct mount *mp, struct vnode **vpp));
+int ufs_quotactl __P((struct mount *mp, int cmds, int uid, /* should be uid_t */
+       caddr_t arg, struct proc *p));
+int ufs_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p));
+int ufs_sync __P((struct mount *mp, int waitfor));
+int ufs_fhtovp __P((struct mount *mp, struct fid *fhp, struct vnode **vpp));
+int ufs_vptofh __P((struct vnode *vp, struct fid *fhp));
+int ufs_init __P(());
diff --git a/usr/src/sys.386bsd/vm/device_pager.h b/usr/src/sys.386bsd/vm/device_pager.h
new file mode 100644 (file)
index 0000000..9130bdb
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1990 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)device_pager.h      7.1 (Berkeley) 12/5/90
+ */
+
+#ifndef        _DEVICE_PAGER_
+#define        _DEVICE_PAGER_  1
+
+/*
+ * Device pager private data.
+ */
+struct devpager {
+       queue_head_t    devp_list;      /* list of managed devices */
+       dev_t           devp_dev;       /* devno of device */
+       vm_page_t       devp_pages;     /* page structs for device */
+       int             devp_npages;    /* size of device in pages */
+       int             devp_count;     /* reference count */
+       vm_object_t     devp_object;    /* object representing this device */
+};
+typedef struct devpager        *dev_pager_t;
+
+#define DEV_PAGER_NULL ((dev_pager_t)0)
+
+#ifdef KERNEL
+
+void           dev_pager_init();
+vm_pager_t     dev_pager_alloc();
+void           dev_pager_dealloc();
+boolean_t      dev_pager_getpage(), dev_pager_putpage();
+boolean_t      dev_pager_haspage();
+
+struct pagerops devicepagerops = {
+       dev_pager_init,
+       dev_pager_alloc,
+       dev_pager_dealloc,
+       dev_pager_getpage,
+       dev_pager_putpage,
+       dev_pager_haspage
+};
+
+#endif
+
+#endif /* _DEVICE_PAGER_ */
diff --git a/usr/src/sys.386bsd/vm/kern_lock.c b/usr/src/sys.386bsd/vm/kern_lock.c
new file mode 100644 (file)
index 0000000..4f0eaf7
--- /dev/null
@@ -0,0 +1,533 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kern_lock.c 7.4 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Locking primitives implementation
+ */
+
+#include "param.h"
+#include "vm_param.h"
+#include "lock.h"
+
+/* XXX */
+#include "proc.h"
+typedef        int *thread_t;
+#define        current_thread()        ((thread_t)&curproc->p_thread)
+/* XXX */
+
+#if    NCPUS > 1
+
+/*
+ *     Module:         lock
+ *     Function:
+ *             Provide reader/writer sychronization.
+ *     Implementation:
+ *             Simple interlock on a bit.  Readers first interlock
+ *             increment the reader count, then let go.  Writers hold
+ *             the interlock (thus preventing further readers), and
+ *             wait for already-accepted readers to go away.
+ */
+
+/*
+ *     The simple-lock routines are the primitives out of which
+ *     the lock package is built.  The implementation is left
+ *     to the machine-dependent code.
+ */
+
+#ifdef notdef
+/*
+ *     A sample implementation of simple locks.
+ *     assumes:
+ *             boolean_t test_and_set(boolean_t *)
+ *                     indivisibly sets the boolean to TRUE
+ *                     and returns its old value
+ *             and that setting a boolean to FALSE is indivisible.
+ */
+/*
+ *     simple_lock_init initializes a simple lock.  A simple lock
+ *     may only be used for exclusive locks.
+ */
+
+void simple_lock_init(l)
+       simple_lock_t   l;
+{
+       *(boolean_t *)l = FALSE;
+}
+
+void simple_lock(l)
+       simple_lock_t   l;
+{
+       while (test_and_set((boolean_t *)l))
+               continue;
+}
+
+void simple_unlock(l)
+       simple_lock_t   l;
+{
+       *(boolean_t *)l = FALSE;
+}
+
+boolean_t simple_lock_try(l)
+       simple_lock_t   l;
+{
+       return (!test_and_set((boolean_t *)l));
+}
+#endif notdef
+#endif NCPUS > 1
+
+#if    NCPUS > 1
+int lock_wait_time = 100;
+#else  NCPUS > 1
+
+       /*
+        *      It is silly to spin on a uni-processor as if we
+        *      thought something magical would happen to the
+        *      want_write bit while we are executing.
+        */
+int lock_wait_time = 0;
+#endif NCPUS > 1
+
+
+/*
+ *     Routine:        lock_init
+ *     Function:
+ *             Initialize a lock; required before use.
+ *             Note that clients declare the "struct lock"
+ *             variables and then initialize them, rather
+ *             than getting a new one from this module.
+ */
+void lock_init(l, can_sleep)
+       lock_t          l;
+       boolean_t       can_sleep;
+{
+       bzero(l, sizeof(lock_data_t));
+       simple_lock_init(&l->interlock);
+       l->want_write = FALSE;
+       l->want_upgrade = FALSE;
+       l->read_count = 0;
+       l->can_sleep = can_sleep;
+       l->thread = (char *)-1;         /* XXX */
+       l->recursion_depth = 0;
+}
+
+void lock_sleepable(l, can_sleep)
+       lock_t          l;
+       boolean_t       can_sleep;
+{
+       simple_lock(&l->interlock);
+       l->can_sleep = can_sleep;
+       simple_unlock(&l->interlock);
+}
+
+
+/*
+ *     Sleep locks.  These use the same data structure and algorithm
+ *     as the spin locks, but the process sleeps while it is waiting
+ *     for the lock.  These work on uniprocessor systems.
+ */
+
+void lock_write(l)
+       register lock_t l;
+{
+       register int    i;
+
+       simple_lock(&l->interlock);
+
+       if (((thread_t)l->thread) == current_thread()) {
+               /*
+                *      Recursive lock.
+                */
+               l->recursion_depth++;
+               simple_unlock(&l->interlock);
+               return;
+       }
+
+       /*
+        *      Try to acquire the want_write bit.
+        */
+       while (l->want_write) {
+               if ((i = lock_wait_time) > 0) {
+                       simple_unlock(&l->interlock);
+                       while (--i > 0 && l->want_write)
+                               continue;
+                       simple_lock(&l->interlock);
+               }
+
+               if (l->can_sleep && l->want_write) {
+                       l->waiting = TRUE;
+                       thread_sleep((int) l, &l->interlock, FALSE);
+                       simple_lock(&l->interlock);
+               }
+       }
+       l->want_write = TRUE;
+
+       /* Wait for readers (and upgrades) to finish */
+
+       while ((l->read_count != 0) || l->want_upgrade) {
+               if ((i = lock_wait_time) > 0) {
+                       simple_unlock(&l->interlock);
+                       while (--i > 0 && (l->read_count != 0 ||
+                                       l->want_upgrade))
+                               continue;
+                       simple_lock(&l->interlock);
+               }
+
+               if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
+                       l->waiting = TRUE;
+                       thread_sleep((int) l, &l->interlock, FALSE);
+                       simple_lock(&l->interlock);
+               }
+       }
+       simple_unlock(&l->interlock);
+}
+
+void lock_done(l)
+       register lock_t l;
+{
+       simple_lock(&l->interlock);
+
+       if (l->read_count != 0)
+               l->read_count--;
+       else
+       if (l->recursion_depth != 0)
+               l->recursion_depth--;
+       else
+       if (l->want_upgrade)
+               l->want_upgrade = FALSE;
+       else
+               l->want_write = FALSE;
+
+       if (l->waiting) {
+               l->waiting = FALSE;
+               thread_wakeup((int) l);
+       }
+       simple_unlock(&l->interlock);
+}
+
+void lock_read(l)
+       register lock_t l;
+{
+       register int    i;
+
+       simple_lock(&l->interlock);
+
+       if (((thread_t)l->thread) == current_thread()) {
+               /*
+                *      Recursive lock.
+                */
+               l->read_count++;
+               simple_unlock(&l->interlock);
+               return;
+       }
+
+       while (l->want_write || l->want_upgrade) {
+               if ((i = lock_wait_time) > 0) {
+                       simple_unlock(&l->interlock);
+                       while (--i > 0 && (l->want_write || l->want_upgrade))
+                               continue;
+                       simple_lock(&l->interlock);
+               }
+
+               if (l->can_sleep && (l->want_write || l->want_upgrade)) {
+                       l->waiting = TRUE;
+                       thread_sleep((int) l, &l->interlock, FALSE);
+                       simple_lock(&l->interlock);
+               }
+       }
+
+       l->read_count++;
+       simple_unlock(&l->interlock);
+}
+
+/*
+ *     Routine:        lock_read_to_write
+ *     Function:
+ *             Improves a read-only lock to one with
+ *             write permission.  If another reader has
+ *             already requested an upgrade to a write lock,
+ *             no lock is held upon return.
+ *
+ *             Returns TRUE if the upgrade *failed*.
+ */
+boolean_t lock_read_to_write(l)
+       register lock_t l;
+{
+       register int    i;
+
+       simple_lock(&l->interlock);
+
+       l->read_count--;
+
+       if (((thread_t)l->thread) == current_thread()) {
+               /*
+                *      Recursive lock.
+                */
+               l->recursion_depth++;
+               simple_unlock(&l->interlock);
+               return(FALSE);
+       }
+
+       if (l->want_upgrade) {
+               /*
+                *      Someone else has requested upgrade.
+                *      Since we've released a read lock, wake
+                *      him up.
+                */
+               if (l->waiting) {
+                       l->waiting = FALSE;
+                       thread_wakeup((int) l);
+               }
+
+               simple_unlock(&l->interlock);
+               return (TRUE);
+       }
+
+       l->want_upgrade = TRUE;
+
+       while (l->read_count != 0) {
+               if ((i = lock_wait_time) > 0) {
+                       simple_unlock(&l->interlock);
+                       while (--i > 0 && l->read_count != 0)
+                               continue;
+                       simple_lock(&l->interlock);
+               }
+
+               if (l->can_sleep && l->read_count != 0) {
+                       l->waiting = TRUE;
+                       thread_sleep((int) l, &l->interlock, FALSE);
+                       simple_lock(&l->interlock);
+               }
+       }
+
+       simple_unlock(&l->interlock);
+       return (FALSE);
+}
+
+void lock_write_to_read(l)
+       register lock_t l;
+{
+       simple_lock(&l->interlock);
+
+       l->read_count++;
+       if (l->recursion_depth != 0)
+               l->recursion_depth--;
+       else
+       if (l->want_upgrade)
+               l->want_upgrade = FALSE;
+       else
+               l->want_write = FALSE;
+
+       if (l->waiting) {
+               l->waiting = FALSE;
+               thread_wakeup((int) l);
+       }
+
+       simple_unlock(&l->interlock);
+}
+
+
+/*
+ *     Routine:        lock_try_write
+ *     Function:
+ *             Tries to get a write lock.
+ *
+ *             Returns FALSE if the lock is not held on return.
+ */
+
+boolean_t lock_try_write(l)
+       register lock_t l;
+{
+
+       simple_lock(&l->interlock);
+
+       if (((thread_t)l->thread) == current_thread()) {
+               /*
+                *      Recursive lock
+                */
+               l->recursion_depth++;
+               simple_unlock(&l->interlock);
+               return(TRUE);
+       }
+
+       if (l->want_write || l->want_upgrade || l->read_count) {
+               /*
+                *      Can't get lock.
+                */
+               simple_unlock(&l->interlock);
+               return(FALSE);
+       }
+
+       /*
+        *      Have lock.
+        */
+
+       l->want_write = TRUE;
+       simple_unlock(&l->interlock);
+       return(TRUE);
+}
+
+/*
+ *     Routine:        lock_try_read
+ *     Function:
+ *             Tries to get a read lock.
+ *
+ *             Returns FALSE if the lock is not held on return.
+ */
+
+boolean_t lock_try_read(l)
+       register lock_t l;
+{
+       simple_lock(&l->interlock);
+
+       if (((thread_t)l->thread) == current_thread()) {
+               /*
+                *      Recursive lock
+                */
+               l->read_count++;
+               simple_unlock(&l->interlock);
+               return(TRUE);
+       }
+
+       if (l->want_write || l->want_upgrade) {
+               simple_unlock(&l->interlock);
+               return(FALSE);
+       }
+
+       l->read_count++;
+       simple_unlock(&l->interlock);
+       return(TRUE);
+}
+
+/*
+ *     Routine:        lock_try_read_to_write
+ *     Function:
+ *             Improves a read-only lock to one with
+ *             write permission.  If another reader has
+ *             already requested an upgrade to a write lock,
+ *             the read lock is still held upon return.
+ *
+ *             Returns FALSE if the upgrade *failed*.
+ */
+boolean_t lock_try_read_to_write(l)
+       register lock_t l;
+{
+
+       simple_lock(&l->interlock);
+
+       if (((thread_t)l->thread) == current_thread()) {
+               /*
+                *      Recursive lock
+                */
+               l->read_count--;
+               l->recursion_depth++;
+               simple_unlock(&l->interlock);
+               return(TRUE);
+       }
+
+       if (l->want_upgrade) {
+               simple_unlock(&l->interlock);
+               return(FALSE);
+       }
+       l->want_upgrade = TRUE;
+       l->read_count--;
+
+       while (l->read_count != 0) {
+               l->waiting = TRUE;
+               thread_sleep((int) l, &l->interlock, FALSE);
+               simple_lock(&l->interlock);
+       }
+
+       simple_unlock(&l->interlock);
+       return(TRUE);
+}
+
+/*
+ *     Allow a process that has a lock for write to acquire it
+ *     recursively (for read, write, or update).
+ */
+void lock_set_recursive(l)
+       lock_t          l;
+{
+       simple_lock(&l->interlock);
+       if (!l->want_write) {
+               panic("lock_set_recursive: don't have write lock");
+       }
+       l->thread = (char *) current_thread();
+       simple_unlock(&l->interlock);
+}
+
+/*
+ *     Prevent a lock from being re-acquired.
+ */
+void lock_clear_recursive(l)
+       lock_t          l;
+{
+       simple_lock(&l->interlock);
+       if (((thread_t) l->thread) != current_thread()) {
+               panic("lock_clear_recursive: wrong thread");
+       }
+       if (l->recursion_depth == 0)
+               l->thread = (char *)-1;         /* XXX */
+       simple_unlock(&l->interlock);
+}
diff --git a/usr/src/sys.386bsd/vm/lock.h b/usr/src/sys.386bsd/vm/lock.h
new file mode 100644 (file)
index 0000000..fdd00d9
--- /dev/null
@@ -0,0 +1,175 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)lock.h      7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Locking primitives definitions
+ */
+
+#ifndef        _LOCK_H_
+#define        _LOCK_H_
+
+#define        NCPUS   1               /* XXX */
+
+/*
+ *     A simple spin lock.
+ */
+
+struct slock {
+       int             lock_data;      /* in general 1 bit is sufficient */
+};
+
+typedef struct slock   simple_lock_data_t;
+typedef struct slock   *simple_lock_t;
+
+/*
+ *     The general lock structure.  Provides for multiple readers,
+ *     upgrading from read to write, and sleeping until the lock
+ *     can be gained.
+ */
+
+struct lock {
+#ifdef vax
+       /*
+        *      Efficient VAX implementation -- see field description below.
+        */
+       unsigned int    read_count:16,
+                       want_upgrade:1,
+                       want_write:1,
+                       waiting:1,
+                       can_sleep:1,
+                       :0;
+
+       simple_lock_data_t      interlock;
+#else  vax
+#ifdef ns32000
+       /*
+        *      Efficient ns32000 implementation --
+        *      see field description below.
+        */
+       simple_lock_data_t      interlock;
+       unsigned int    read_count:16,
+                       want_upgrade:1,
+                       want_write:1,
+                       waiting:1,
+                       can_sleep:1,
+                       :0;
+
+#else  ns32000
+       /*      Only the "interlock" field is used for hardware exclusion;
+        *      other fields are modified with normal instructions after
+        *      acquiring the interlock bit.
+        */
+       simple_lock_data_t
+                       interlock;      /* Interlock for remaining fields */
+       boolean_t       want_write;     /* Writer is waiting, or locked for write */
+       boolean_t       want_upgrade;   /* Read-to-write upgrade waiting */
+       boolean_t       waiting;        /* Someone is sleeping on lock */
+       boolean_t       can_sleep;      /* Can attempts to lock go to sleep */
+       int             read_count;     /* Number of accepted readers */
+#endif /* ns32000 */
+#endif /* vax */
+       char            *thread;        /* Thread that has lock, if recursive locking allowed */
+                                       /* (should be thread_t, but but we then have mutually
+                                          recursive definitions) */
+       int             recursion_depth;/* Depth of recursion */
+};
+
+typedef struct lock    lock_data_t;
+typedef struct lock    *lock_t;
+
+#if    NCPUS > 1
+void           simple_lock_init();
+void           simple_lock();
+void           simple_unlock();
+boolean_t      simple_lock_try();
+#else  NCPUS > 1
+/*
+ *     No multiprocessor locking is necessary.
+ */
+#define simple_lock_init(l)
+#define simple_lock(l)
+#define simple_unlock(l)
+#define simple_lock_try(l)     (1)     /* always succeeds */
+#endif /* NCPUS > 1 */
+
+/* Sleep locks must work even if no multiprocessing */
+
+void           lock_init();
+void           lock_sleepable();
+void           lock_write();
+void           lock_read();
+void           lock_done();
+boolean_t      lock_read_to_write();
+void           lock_write_to_read();
+boolean_t      lock_try_write();
+boolean_t      lock_try_read();
+boolean_t      lock_try_read_to_write();
+
+#define        lock_read_done(l)       lock_done(l)
+#define        lock_write_done(l)      lock_done(l)
+
+void           lock_set_recursive();
+void           lock_clear_recursive();
+
+#endif /* !_LOCK_H_ */
diff --git a/usr/src/sys.386bsd/vm/pmap.h b/usr/src/sys.386bsd/vm/pmap.h
new file mode 100644 (file)
index 0000000..0dd019b
--- /dev/null
@@ -0,0 +1,107 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)pmap.h      7.4 (Berkeley) 5/7/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Avadis Tevanian, Jr.
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Machine address mapping definitions -- machine-independent
+ *     section.  [For machine-dependent section, see "machine/pmap.h".]
+ */
+
+#ifndef        _PMAP_VM_
+#define        _PMAP_VM_
+
+#include <machine/pmap.h>
+
+#ifdef KERNEL
+void           pmap_bootstrap();
+void           pmap_init();
+void           pmap_pinit __P((struct pmap *pmap));
+void           pmap_release __P((struct pmap *pmap));
+vm_offset_t    pmap_map();
+pmap_t         pmap_create();
+void           pmap_destroy();
+void           pmap_reference();
+void           pmap_remove();
+void           pmap_page_protect();
+void           pmap_protect();
+void           pmap_enter();
+vm_offset_t    pmap_extract();
+void           pmap_update();
+void           pmap_collect();
+void           pmap_activate();
+void           pmap_deactivate();
+void           pmap_copy();
+void           pmap_statistics();
+void           pmap_clear_reference();
+boolean_t      pmap_is_referenced();
+#ifndef pmap_kernel
+pmap_t         pmap_kernel();
+#endif
+
+void           pmap_redzone();
+boolean_t      pmap_access();
+
+extern pmap_t  kernel_pmap;
+#endif
+
+#endif _PMAP_VM_
diff --git a/usr/src/sys.386bsd/vm/queue.h b/usr/src/sys.386bsd/vm/queue.h
new file mode 100644 (file)
index 0000000..00175ba
--- /dev/null
@@ -0,0 +1,133 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Avadis Tevanian, Jr.
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Type definitions for generic queues.
+ */
+
+#ifndef        _QUEUE_H_
+#define        _QUEUE_H_
+
+struct queue_entry {
+       struct queue_entry      *next;          /* next element */
+       struct queue_entry      *prev;          /* previous element */
+};
+
+typedef struct queue_entry     *queue_t;
+typedef        struct queue_entry      queue_head_t;
+typedef        struct queue_entry      queue_chain_t;
+typedef        struct queue_entry      *queue_entry_t;
+
+#define round_queue(size)      (((size)+7) & (~7))
+
+#define enqueue(queue,elt)     enqueue_tail(queue, elt)
+#define        dequeue(queue)          dequeue_head(queue)
+
+#define        enqueue_head(queue,elt) insque(elt,queue)
+#define        enqueue_tail(queue,elt) insque(elt,(queue)->prev)
+#define        remqueue(queue,elt)     remque(elt)
+
+#define        queue_init(q)           ((q)->next = (q)->prev = q)
+#define        queue_first(q)          ((q)->next)
+#define        queue_next(qc)          ((qc)->next)
+#define        queue_end(q, qe)        ((q) == (qe))
+#define        queue_empty(q)          queue_end((q), queue_first(q))
+
+#define queue_enter(head, elt, type, field) {                  \
+       if (queue_empty((head))) {                              \
+               (head)->next = (queue_entry_t) elt;             \
+               (head)->prev = (queue_entry_t) elt;             \
+               (elt)->field.next = head;                       \
+               (elt)->field.prev = head;                       \
+       } else {                                                \
+               register queue_entry_t prev = (head)->prev;     \
+               (elt)->field.prev = prev;                       \
+               (elt)->field.next = head;                       \
+               (head)->prev = (queue_entry_t)(elt);            \
+               ((type)prev)->field.next = (queue_entry_t)(elt);\
+       }                                                       \
+}
+
+#define        queue_field(head, thing, type, field)                   \
+               (((head) == (thing)) ? (head) : &((type)(thing))->field)
+
+#define        queue_remove(head, elt, type, field) {                  \
+       register queue_entry_t next = (elt)->field.next;        \
+       register queue_entry_t prev = (elt)->field.prev;        \
+       queue_field((head), next, type, field)->prev = prev;    \
+       queue_field((head), prev, type, field)->next = next;    \
+}
+
+#define        queue_assign(to, from, type, field) {                   \
+       ((type)((from)->prev))->field.next = (to);              \
+       ((type)((from)->next))->field.prev = (to);              \
+       *to = *from;                                            \
+}
+
+#define        queue_remove_first(h, e, t, f) {                        \
+       e = (t) queue_first((h));                               \
+       queue_remove((h), (e), t, f);                           \
+}
+
+#endif /* !_QUEUE_H_ */
diff --git a/usr/src/sys.386bsd/vm/swap_pager.h b/usr/src/sys.386bsd/vm/swap_pager.h
new file mode 100644 (file)
index 0000000..7e9ea79
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1990 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)swap_pager.h        7.1 (Berkeley) 12/5/90
+ */
+
+#ifndef        _SWAP_PAGER_
+#define        _SWAP_PAGER_    1
+
+/*
+ * In the swap pager, the backing store for an object is organized as an
+ * array of some number of "swap blocks".  A swap block consists of a bitmask
+ * and some number of contiguous DEV_BSIZE disk blocks.  The minimum size
+ * of a swap block is:
+ *
+ *     max(PAGE_SIZE, dmmin*DEV_BSIZE)                 [ 32k currently ]
+ *
+ * bytes (since the pager interface is page oriented), the maximum size is:
+ *
+ *     min(#bits(swb_mask)*PAGE_SIZE, dmmax*DEV_BSIZE) [ 128k currently ]
+ *
+ * where dmmin and dmmax are left over from the old VM interface.  The bitmask
+ * (swb_mask) is used by swap_pager_haspage() to determine if a particular
+ * page has actually been written; i.e. the pager copy of the page is valid.
+ * All swap blocks in the backing store of an object will be the same size.
+ *
+ * The reason for variable sized swap blocks is to reduce fragmentation of
+ * swap resources.  Whenever possible we allocate smaller swap blocks to
+ * smaller objects.  The swap block size is determined from a table of
+ * object-size vs. swap-block-size computed at boot time.
+ */
+typedef        int     sw_bm_t;        /* pager bitmask */
+
+struct swblock {
+       sw_bm_t  swb_mask;      /* bitmask of valid pages in this block */
+       daddr_t  swb_block;     /* starting disk block for this block */
+};
+typedef struct swblock *sw_blk_t;
+
+/*
+ * Swap pager private data.
+ */
+struct swpager {
+       vm_size_t    sw_osize;  /* size of object we are backing (bytes) */
+       int          sw_bsize;  /* size of swap blocks (DEV_BSIZE units) */
+       int          sw_nblocks;/* number of blocks in list (sw_blk_t units) */
+       sw_blk_t     sw_blocks; /* pointer to list of swap blocks */
+       short        sw_flags;  /* flags */
+       short        sw_poip;   /* pageouts in progress */
+};
+typedef struct swpager *sw_pager_t;
+
+#define        SW_WANTED       0x01
+#define SW_NAMED       0x02
+
+#ifdef KERNEL
+
+void           swap_pager_init();
+vm_pager_t     swap_pager_alloc();
+void           swap_pager_dealloc();
+boolean_t      swap_pager_getpage(), swap_pager_putpage();
+boolean_t      swap_pager_haspage();
+
+struct pagerops swappagerops = {
+       swap_pager_init,
+       swap_pager_alloc,
+       swap_pager_dealloc,
+       swap_pager_getpage,
+       swap_pager_putpage,
+       swap_pager_haspage
+};
+
+int            swap_pager_iodone();
+boolean_t      swap_pager_clean();
+
+#endif
+
+#endif /* _SWAP_PAGER_ */
diff --git a/usr/src/sys.386bsd/vm/vm.h b/usr/src/sys.386bsd/vm/vm.h
new file mode 100644 (file)
index 0000000..2f7d244
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm.h        7.1 (Berkeley) 5/5/91
+ */
+
+#ifndef VM_H
+#define VM_H
+#include <vm/vm_param.h>
+#include <vm/lock.h>
+#include <vm/queue.h>
+#include <vm/vm_prot.h>
+#include <vm/vm_inherit.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_statistics.h>
+#include <vm/pmap.h>
+
+/*
+ * Shareable process virtual address space.
+ * May eventually be merged with vm_map.
+ * Several fields are temporary (text, data stuff).
+ */
+struct vmspace {
+       struct  vm_map vm_map;  /* VM address map */
+       struct  pmap vm_pmap;   /* private physical map */
+       int     vm_refcnt;      /* number of references */
+       caddr_t vm_shm;         /* SYS5 shared memory private data XXX */
+/* we copy from vm_startcopy to the end of the structure on fork */
+#define vm_startcopy vm_rssize
+       segsz_t vm_rssize;      /* current resident set size in pages */
+       segsz_t vm_swrss;       /* resident set size before last swap */
+       segsz_t vm_tsize;       /* text size (pages) XXX */
+       segsz_t vm_dsize;       /* data size (pages) XXX */
+       segsz_t vm_ssize;       /* stack size (pages) */
+       caddr_t vm_taddr;       /* user virtual address of text XXX */
+       caddr_t vm_daddr;       /* user virtual address of data XXX */
+       caddr_t vm_maxsaddr;    /* user VA at max stack growth */
+};
+
+struct vmspace *vmspace_alloc __P((vm_offset_t min, vm_offset_t max,
+                       int pageable));
+struct vmspace *vmspace_fork __P((struct vmspace *));
+void   vmspace_free __P((struct vmspace *));
+#endif /* VM_H */
diff --git a/usr/src/sys.386bsd/vm/vm_inherit.h b/usr/src/sys.386bsd/vm/vm_inherit.h
new file mode 100644 (file)
index 0000000..c185845
--- /dev/null
@@ -0,0 +1,91 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_inherit.h        7.2 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Virtual memory map inheritance definitions.
+ */
+
+#ifndef        _VM_INHERIT_
+#define        _VM_INHERIT_
+
+/*
+ *     Types defined:
+ *
+ *     vm_inherit_t    inheritance codes.
+ */
+
+typedef int            vm_inherit_t;   /* might want to change this */
+
+/*
+ *     Enumeration of valid values for vm_inherit_t.
+ */
+
+#define        VM_INHERIT_SHARE        ((vm_inherit_t) 0)      /* share with child */
+#define        VM_INHERIT_COPY         ((vm_inherit_t) 1)      /* copy into child */
+#define VM_INHERIT_NONE                ((vm_inherit_t) 2)      /* absent from child */
+#define        VM_INHERIT_DONATE_COPY  ((vm_inherit_t) 3)      /* copy and delete */
+
+#define VM_INHERIT_DEFAULT     VM_INHERIT_COPY
+
+#endif _VM_INHERIT_
diff --git a/usr/src/sys.386bsd/vm/vm_init.c b/usr/src/sys.386bsd/vm/vm_init.c
new file mode 100644 (file)
index 0000000..e18f64a
--- /dev/null
@@ -0,0 +1,102 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_init.c   7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Initialize the Virtual Memory subsystem.
+ */
+
+#include "param.h"
+
+#include "vm.h"
+#include "vm_page.h"
+#include "vm_kern.h"
+
+/*
+ *     vm_init initializes the virtual memory system.
+ *     This is done only by the first cpu up.
+ *
+ *     The start and end address of physical memory is passed in.
+ */
+
+void vm_mem_init()
+{
+       extern vm_offset_t      avail_start, avail_end;
+       extern vm_offset_t      virtual_avail, virtual_end;
+
+       /*
+        *      Initializes resident memory structures.
+        *      From here on, all physical memory is accounted for,
+        *      and we use only virtual addresses.
+        */
+
+       virtual_avail = vm_page_startup(avail_start, avail_end, virtual_avail);
+       /*
+        * Initialize other VM packages
+        */
+       vm_object_init();
+       vm_map_startup();
+       kmem_init(virtual_avail, virtual_end);
+       pmap_init(avail_start, avail_end);
+       vm_pager_init();
+}
diff --git a/usr/src/sys.386bsd/vm/vm_map.h b/usr/src/sys.386bsd/vm/vm_map.h
new file mode 100644 (file)
index 0000000..719c984
--- /dev/null
@@ -0,0 +1,204 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_map.h    7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Virtual memory map module definitions.
+ */
+
+#ifndef        _VM_MAP_
+#define        _VM_MAP_
+
+/*
+ *     Types defined:
+ *
+ *     vm_map_t                the high-level address map data structure.
+ *     vm_map_entry_t          an entry in an address map.
+ *     vm_map_version_t        a timestamp of a map, for use with vm_map_lookup
+ */
+
+/*
+ *     Objects which live in maps may be either VM objects, or
+ *     another map (called a "sharing map") which denotes read-write
+ *     sharing with other maps.
+ */
+
+union vm_map_object {
+       struct vm_object        *vm_object;     /* object object */
+       struct vm_map           *share_map;     /* share map */
+       struct vm_map           *sub_map;       /* belongs to another map */
+};
+
+typedef union vm_map_object    vm_map_object_t;
+
+/*
+ *     Address map entries consist of start and end addresses,
+ *     a VM object (or sharing map) and offset into that object,
+ *     and user-exported inheritance and protection information.
+ *     Also included is control information for virtual copy operations.
+ */
+struct vm_map_entry {
+       struct vm_map_entry     *prev;          /* previous entry */
+       struct vm_map_entry     *next;          /* next entry */
+       vm_offset_t             start;          /* start address */
+       vm_offset_t             end;            /* end address */
+       union vm_map_object     object;         /* object I point to */
+       vm_offset_t             offset;         /* offset into object */
+       boolean_t               is_a_map;       /* Is "object" a map? */
+       boolean_t               is_sub_map;     /* Is "object" a submap? */
+               /* Only in sharing maps: */
+       boolean_t               copy_on_write;  /* is data copy-on-write */
+       boolean_t               needs_copy;     /* does object need to be copied */
+               /* Only in task maps: */
+       vm_prot_t               protection;     /* protection code */
+       vm_prot_t               max_protection; /* maximum protection */
+       vm_inherit_t            inheritance;    /* inheritance */
+       int                     wired_count;    /* can be paged if = 0 */
+};
+
+typedef struct vm_map_entry    *vm_map_entry_t;
+
+/*
+ *     Maps are doubly-linked lists of map entries, kept sorted
+ *     by address.  A single hint is provided to start
+ *     searches again from the last successful search,
+ *     insertion, or removal.
+ */
+struct vm_map {
+       struct pmap *           pmap;           /* Physical map */
+       lock_data_t             lock;           /* Lock for map data */
+       struct vm_map_entry     header;         /* List of entries */
+       int                     nentries;       /* Number of entries */
+       vm_size_t               size;           /* virtual size */
+       boolean_t               is_main_map;    /* Am I a main map? */
+       int                     ref_count;      /* Reference count */
+       simple_lock_data_t      ref_lock;       /* Lock for ref_count field */
+       vm_map_entry_t          hint;           /* hint for quick lookups */
+       simple_lock_data_t      hint_lock;      /* lock for hint storage */
+       vm_map_entry_t          first_free;     /* First free space hint */
+       boolean_t               entries_pageable; /* map entries pageable?? */
+       unsigned int            timestamp;      /* Version number */
+#define        min_offset              header.start
+#define max_offset             header.end
+};
+
+typedef        struct vm_map   *vm_map_t;
+
+/*
+ *     Map versions are used to validate a previous lookup attempt.
+ *
+ *     Since lookup operations may involve both a main map and
+ *     a sharing map, it is necessary to have a timestamp from each.
+ *     [If the main map timestamp has changed, the share_map and
+ *     associated timestamp are no longer valid; the map version
+ *     does not include a reference for the imbedded share_map.]
+ */
+typedef struct {
+       int             main_timestamp;
+       vm_map_t        share_map;
+       int             share_timestamp;
+} vm_map_version_t;
+
+/*
+ *     Macros:         vm_map_lock, etc.
+ *     Function:
+ *             Perform locking on the data portion of a map.
+ */
+
+#define                vm_map_lock(map)        { lock_write(&(map)->lock); (map)->timestamp++; }
+#define                vm_map_unlock(map)      lock_write_done(&(map)->lock)
+#define                vm_map_lock_read(map)   lock_read(&(map)->lock)
+#define                vm_map_unlock_read(map) lock_read_done(&(map)->lock)
+
+/*
+ *     Exported procedures that operate on vm_map_t.
+ */
+
+void           vm_map_init();
+vm_map_t       vm_map_create();
+void           vm_map_deallocate();
+void           vm_map_reference();
+int            vm_map_find();
+int            vm_map_remove();
+int            vm_map_lookup();
+void           vm_map_lookup_done();
+int            vm_map_protect();
+int            vm_map_inherit();
+int            vm_map_copy();
+void           vm_map_print();
+void           vm_map_copy_entry();
+boolean_t      vm_map_verify();
+void           vm_map_verify_done();
+
+/*
+ *     Functions implemented as macros
+ */
+#define                vm_map_min(map)         ((map)->min_offset)
+#define                vm_map_max(map)         ((map)->max_offset)
+#define                vm_map_pmap(map)        ((map)->pmap)
+
+/* XXX: number of kernel maps and entries to statically allocate */
+#define MAX_KMAP       10
+#define        MAX_KMAPENT     500
+
+#endif _VM_MAP_
diff --git a/usr/src/sys.386bsd/vm/vm_meter.c b/usr/src/sys.386bsd/vm/vm_meter.c
new file mode 100644 (file)
index 0000000..e1dfaa3
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_meter.c  7.11 (Berkeley) 4/20/91
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "kernel.h"
+
+#include "vm_param.h"
+#include "vmmeter.h"
+
+fixpt_t        averunnable[3];         /* load average, of runnable procs */
+
+int    maxslp = MAXSLP;
+int    saferss = SAFERSS;
+
+
+vmmeter()
+{
+       register unsigned *cp, *rp, *sp;
+
+       if (time.tv_sec % 5 == 0)
+               vmtotal();
+       if (proc0.p_slptime > maxslp/2)
+               wakeup((caddr_t)&proc0);
+}
+
+vmtotal()
+{
+       register struct proc *p;
+       int nrun = 0;
+
+       total.t_vm = 0;
+       total.t_avm = 0;
+       total.t_rm = 0;
+       total.t_arm = 0;
+       total.t_rq = 0;
+       total.t_dw = 0;
+       total.t_pw = 0;
+       total.t_sl = 0;
+       total.t_sw = 0;
+       for (p = allproc; p != NULL; p = p->p_nxt) {
+               if (p->p_flag & SSYS)
+                       continue;
+               if (p->p_stat) {
+                       switch (p->p_stat) {
+
+                       case SSLEEP:
+                               if (p->p_pri <= PZERO && p->p_slptime == 0)
+                                       nrun++;
+                               /* fall through */
+                       case SSTOP:
+#ifdef notdef
+                               if (p->p_flag & SPAGE)
+                                       total.t_pw++;
+                               else
+#endif
+                               if (p->p_flag & SLOAD) {
+                                       if (p->p_pri <= PZERO)
+                                               total.t_dw++;
+                                       else if (p->p_slptime < maxslp)
+                                               total.t_sl++;
+                               } else if (p->p_slptime < maxslp)
+                                       total.t_sw++;
+                               if (p->p_slptime < maxslp)
+                                       goto active;
+                               break;
+
+                       case SRUN:
+                       case SIDL:
+                               nrun++;
+                               if (p->p_flag & SLOAD)
+                                       total.t_rq++;
+                               else
+                                       total.t_sw++;
+active:
+                               break;
+                       }
+               }
+       }
+       loadav(averunnable, nrun);
+}
+
+/*
+ * Constants for averages over 1, 5, and 15 minutes
+ * when sampling at 5 second intervals.
+ */
+fixpt_t        cexp[3] = {
+       0.9200444146293232 * FSCALE,    /* exp(-1/12) */
+       0.9834714538216174 * FSCALE,    /* exp(-1/60) */
+       0.9944598480048967 * FSCALE,    /* exp(-1/180) */
+};
+
+/*
+ * Compute a tenex style load average of a quantity on
+ * 1, 5 and 15 minute intervals.
+ */
+loadav(avg, n)
+       register fixpt_t *avg;
+       int n;
+{
+       register int i;
+
+       for (i = 0; i < 3; i++)
+               avg[i] = (cexp[i] * avg[i] + n * FSCALE * (FSCALE - cexp[i]))
+                        >> FSHIFT;
+#if defined(COMPAT_43) && (defined(vax) || defined(tahoe))
+       for (i = 0; i < 3; i++)
+               avenrun[i] = (double) averunnable[i] / FSCALE;
+#endif /* COMPAT_43 */
+}
diff --git a/usr/src/sys.386bsd/vm/vm_object.c b/usr/src/sys.386bsd/vm/vm_object.c
new file mode 100644 (file)
index 0000000..1c8624f
--- /dev/null
@@ -0,0 +1,1449 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_object.c 7.4 (Berkeley) 5/7/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Virtual memory object module.
+ */
+
+#include "param.h"
+#include "malloc.h"
+
+#include "vm.h"
+#include "vm_page.h"
+
+/*
+ *     Virtual memory objects maintain the actual data
+ *     associated with allocated virtual memory.  A given
+ *     page of memory exists within exactly one object.
+ *
+ *     An object is only deallocated when all "references"
+ *     are given up.  Only one "reference" to a given
+ *     region of an object should be writeable.
+ *
+ *     Associated with each object is a list of all resident
+ *     memory pages belonging to that object; this list is
+ *     maintained by the "vm_page" module, and locked by the object's
+ *     lock.
+ *
+ *     Each object also records a "pager" routine which is
+ *     used to retrieve (and store) pages to the proper backing
+ *     storage.  In addition, objects may be backed by other
+ *     objects from which they were virtual-copied.
+ *
+ *     The only items within the object structure which are
+ *     modified after time of creation are:
+ *             reference count         locked by object's lock
+ *             pager routine           locked by object's lock
+ *
+ */
+
+struct vm_object       kernel_object_store;
+struct vm_object       kmem_object_store;
+
+#define        VM_OBJECT_HASH_COUNT    157
+
+int            vm_cache_max = 100;     /* can patch if necessary */
+queue_head_t   vm_object_hashtable[VM_OBJECT_HASH_COUNT];
+
+long   object_collapses = 0;
+long   object_bypasses  = 0;
+
+/*
+ *     vm_object_init:
+ *
+ *     Initialize the VM objects module.
+ */
+void vm_object_init()
+{
+       register int    i;
+
+       queue_init(&vm_object_cached_list);
+       queue_init(&vm_object_list);
+       vm_object_count = 0;
+       simple_lock_init(&vm_cache_lock);
+       simple_lock_init(&vm_object_list_lock);
+
+       for (i = 0; i < VM_OBJECT_HASH_COUNT; i++)
+               queue_init(&vm_object_hashtable[i]);
+
+       kernel_object = &kernel_object_store;
+       _vm_object_allocate(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
+                       kernel_object);
+
+       kmem_object = &kmem_object_store;
+       _vm_object_allocate(VM_KMEM_SIZE + VM_MBUF_SIZE, kmem_object);
+}
+
+/*
+ *     vm_object_allocate:
+ *
+ *     Returns a new object with the given size.
+ */
+
+vm_object_t vm_object_allocate(size)
+       vm_size_t       size;
+{
+       register vm_object_t    result;
+
+       result = (vm_object_t)
+               malloc((u_long)sizeof *result, M_VMOBJ, M_WAITOK);
+
+       _vm_object_allocate(size, result);
+
+       return(result);
+}
+
+_vm_object_allocate(size, object)
+       vm_size_t               size;
+       register vm_object_t    object;
+{
+       queue_init(&object->memq);
+       vm_object_lock_init(object);
+       object->ref_count = 1;
+       object->resident_page_count = 0;
+       object->size = size;
+       object->can_persist = FALSE;
+       object->paging_in_progress = 0;
+       object->copy = NULL;
+
+       /*
+        *      Object starts out read-write, with no pager.
+        */
+
+       object->pager = NULL;
+       object->pager_ready = FALSE;
+       object->internal = TRUE;        /* vm_allocate_with_pager will reset */
+       object->paging_offset = 0;
+       object->shadow = NULL;
+       object->shadow_offset = (vm_offset_t) 0;
+
+       simple_lock(&vm_object_list_lock);
+       queue_enter(&vm_object_list, object, vm_object_t, object_list);
+       vm_object_count++;
+       simple_unlock(&vm_object_list_lock);
+}
+
+/*
+ *     vm_object_reference:
+ *
+ *     Gets another reference to the given object.
+ */
+void vm_object_reference(object)
+       register vm_object_t    object;
+{
+       if (object == NULL)
+               return;
+
+       vm_object_lock(object);
+       object->ref_count++;
+       vm_object_unlock(object);
+}
+
+/*
+ *     vm_object_deallocate:
+ *
+ *     Release a reference to the specified object,
+ *     gained either through a vm_object_allocate
+ *     or a vm_object_reference call.  When all references
+ *     are gone, storage associated with this object
+ *     may be relinquished.
+ *
+ *     No object may be locked.
+ */
+void vm_object_deallocate(object)
+       register vm_object_t    object;
+{
+       vm_object_t     temp;
+
+       while (object != NULL) {
+
+               /*
+                *      The cache holds a reference (uncounted) to
+                *      the object; we must lock it before removing
+                *      the object.
+                */
+
+               vm_object_cache_lock();
+
+               /*
+                *      Lose the reference
+                */
+               vm_object_lock(object);
+               if (--(object->ref_count) != 0) {
+
+                       /*
+                        *      If there are still references, then
+                        *      we are done.
+                        */
+                       vm_object_unlock(object);
+                       vm_object_cache_unlock();
+                       return;
+               }
+
+               /*
+                *      See if this object can persist.  If so, enter
+                *      it in the cache, then deactivate all of its
+                *      pages.
+                */
+
+               if (object->can_persist) {
+
+                       queue_enter(&vm_object_cached_list, object,
+                               vm_object_t, cached_list);
+                       vm_object_cached++;
+                       vm_object_cache_unlock();
+
+                       vm_object_deactivate_pages(object);
+                       vm_object_unlock(object);
+
+                       vm_object_cache_trim();
+                       return;
+               }
+
+               /*
+                *      Make sure no one can look us up now.
+                */
+               vm_object_remove(object->pager);
+               vm_object_cache_unlock();
+
+               temp = object->shadow;
+               vm_object_terminate(object);
+                       /* unlocks and deallocates object */
+               object = temp;
+       }
+}
+
+
+/*
+ *     vm_object_terminate actually destroys the specified object, freeing
+ *     up all previously used resources.
+ *
+ *     The object must be locked.
+ */
+void vm_object_terminate(object)
+       register vm_object_t    object;
+{
+       register vm_page_t      p;
+       vm_object_t             shadow_object;
+
+       /*
+        *      Detach the object from its shadow if we are the shadow's
+        *      copy.
+        */
+       if ((shadow_object = object->shadow) != NULL) {
+               vm_object_lock(shadow_object);
+               if (shadow_object->copy == object)
+                       shadow_object->copy = NULL;
+#if 0
+               else if (shadow_object->copy != NULL)
+                       panic("vm_object_terminate: copy/shadow inconsistency");
+#endif
+               vm_object_unlock(shadow_object);
+       }
+
+       /*
+        *      Wait until the pageout daemon is through
+        *      with the object.
+        */
+
+       while (object->paging_in_progress != 0) {
+               vm_object_sleep(object, object, FALSE);
+               vm_object_lock(object);
+       }
+
+
+       /*
+        *      While the paging system is locked,
+        *      pull the object's pages off the active
+        *      and inactive queues.  This keeps the
+        *      pageout daemon from playing with them
+        *      during vm_pager_deallocate.
+        *
+        *      We can't free the pages yet, because the
+        *      object's pager may have to write them out
+        *      before deallocating the paging space.
+        */
+
+       p = (vm_page_t) queue_first(&object->memq);
+       while (!queue_end(&object->memq, (queue_entry_t) p)) {
+               VM_PAGE_CHECK(p);
+
+               vm_page_lock_queues();
+               if (p->active) {
+                       queue_remove(&vm_page_queue_active, p, vm_page_t,
+                                               pageq);
+                       p->active = FALSE;
+                       vm_page_active_count--;
+               }
+
+               if (p->inactive) {
+                       queue_remove(&vm_page_queue_inactive, p, vm_page_t,
+                                               pageq);
+                       p->inactive = FALSE;
+                       vm_page_inactive_count--;
+               }
+               vm_page_unlock_queues();
+               p = (vm_page_t) queue_next(&p->listq);
+       }
+                               
+       vm_object_unlock(object);
+
+       if (object->paging_in_progress != 0)
+               panic("vm_object_deallocate: pageout in progress");
+
+       /*
+        *      Clean and free the pages, as appropriate.
+        *      All references to the object are gone,
+        *      so we don't need to lock it.
+        */
+
+       if (!object->internal) {
+               vm_object_lock(object);
+               vm_object_page_clean(object, 0, 0);
+               vm_object_unlock(object);
+       }
+       while (!queue_empty(&object->memq)) {
+               p = (vm_page_t) queue_first(&object->memq);
+
+               VM_PAGE_CHECK(p);
+
+               vm_page_lock_queues();
+               vm_page_free(p);
+               vm_page_unlock_queues();
+       }
+
+       /*
+        *      Let the pager know object is dead.
+        */
+
+       if (object->pager != NULL)
+               vm_pager_deallocate(object->pager);
+
+
+       simple_lock(&vm_object_list_lock);
+       queue_remove(&vm_object_list, object, vm_object_t, object_list);
+       vm_object_count--;
+       simple_unlock(&vm_object_list_lock);
+
+       /*
+        *      Free the space for the object.
+        */
+
+       free((caddr_t)object, M_VMOBJ);
+}
+
+/*
+ *     vm_object_page_clean
+ *
+ *     Clean all dirty pages in the specified range of object.
+ *     Leaves page on whatever queue it is currently on.
+ *
+ *     Odd semantics: if start == end, we clean everything.
+ *
+ *     The object must be locked.
+ */
+vm_object_page_clean(object, start, end)
+       register vm_object_t    object;
+       register vm_offset_t    start;
+       register vm_offset_t    end;
+{
+       register vm_page_t      p;
+
+       if (object->pager == NULL)
+               return;
+
+again:
+       p = (vm_page_t) queue_first(&object->memq);
+       while (!queue_end(&object->memq, (queue_entry_t) p)) {
+               if (start == end ||
+                   p->offset >= start && p->offset < end) {
+                       if (p->clean && pmap_is_modified(VM_PAGE_TO_PHYS(p)))
+                               p->clean = FALSE;
+                       pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
+                       if (!p->clean) {
+                               p->busy = TRUE;
+                               object->paging_in_progress++;
+                               vm_object_unlock(object);
+                               (void) vm_pager_put(object->pager, p, TRUE);
+                               vm_object_lock(object);
+                               object->paging_in_progress--;
+                               p->busy = FALSE;
+                               PAGE_WAKEUP(p);
+                               goto again;
+                       }
+               }
+               p = (vm_page_t) queue_next(&p->listq);
+       }
+}
+
+/*
+ *     vm_object_deactivate_pages
+ *
+ *     Deactivate all pages in the specified object.  (Keep its pages
+ *     in memory even though it is no longer referenced.)
+ *
+ *     The object must be locked.
+ */
+vm_object_deactivate_pages(object)
+       register vm_object_t    object;
+{
+       register vm_page_t      p, next;
+
+       p = (vm_page_t) queue_first(&object->memq);
+       while (!queue_end(&object->memq, (queue_entry_t) p)) {
+               next = (vm_page_t) queue_next(&p->listq);
+               vm_page_lock_queues();
+               vm_page_deactivate(p);
+               vm_page_unlock_queues();
+               p = next;
+       }
+}
+
+/*
+ *     Trim the object cache to size.
+ */
+vm_object_cache_trim()
+{
+       register vm_object_t    object;
+
+       vm_object_cache_lock();
+       while (vm_object_cached > vm_cache_max) {
+               object = (vm_object_t) queue_first(&vm_object_cached_list);
+               vm_object_cache_unlock();
+
+               if (object != vm_object_lookup(object->pager))
+                       panic("vm_object_deactivate: I'm sooo confused.");
+
+               pager_cache(object, FALSE);
+
+               vm_object_cache_lock();
+       }
+       vm_object_cache_unlock();
+}
+
+
+/*
+ *     vm_object_shutdown()
+ *
+ *     Shut down the object system.  Unfortunately, while we
+ *     may be trying to do this, init is happily waiting for
+ *     processes to exit, and therefore will be causing some objects
+ *     to be deallocated.  To handle this, we gain a fake reference
+ *     to all objects we release paging areas for.  This will prevent
+ *     a duplicate deallocation.  This routine is probably full of
+ *     race conditions!
+ */
+
+void vm_object_shutdown()
+{
+       register vm_object_t    object;
+
+       /*
+        *      Clean up the object cache *before* we screw up the reference
+        *      counts on all of the objects.
+        */
+
+       vm_object_cache_clear();
+
+       printf("free paging spaces: ");
+
+       /*
+        *      First we gain a reference to each object so that
+        *      no one else will deallocate them.
+        */
+
+       simple_lock(&vm_object_list_lock);
+       object = (vm_object_t) queue_first(&vm_object_list);
+       while (!queue_end(&vm_object_list, (queue_entry_t) object)) {
+               vm_object_reference(object);
+               object = (vm_object_t) queue_next(&object->object_list);
+       }
+       simple_unlock(&vm_object_list_lock);
+
+       /*
+        *      Now we deallocate all the paging areas.  We don't need
+        *      to lock anything because we've reduced to a single
+        *      processor while shutting down.  This also assumes that
+        *      no new objects are being created.
+        */
+
+       object = (vm_object_t) queue_first(&vm_object_list);
+       while (!queue_end(&vm_object_list, (queue_entry_t) object)) {
+               if (object->pager != NULL)
+                       vm_pager_deallocate(object->pager);
+               object = (vm_object_t) queue_next(&object->object_list);
+               printf(".");
+       }
+       printf("done.\n");
+}
+
+/*
+ *     vm_object_pmap_copy:
+ *
+ *     Makes all physical pages in the specified
+ *     object range copy-on-write.  No writeable
+ *     references to these pages should remain.
+ *
+ *     The object must *not* be locked.
+ */
+void vm_object_pmap_copy(object, start, end)
+       register vm_object_t    object;
+       register vm_offset_t    start;
+       register vm_offset_t    end;
+{
+       register vm_page_t      p;
+
+       if (object == NULL)
+               return;
+
+       vm_object_lock(object);
+       p = (vm_page_t) queue_first(&object->memq);
+       while (!queue_end(&object->memq, (queue_entry_t) p)) {
+               if ((start <= p->offset) && (p->offset < end)) {
+                       pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_READ);
+                       p->copy_on_write = TRUE;
+               }
+               p = (vm_page_t) queue_next(&p->listq);
+       }
+       vm_object_unlock(object);
+}
+
+/*
+ *     vm_object_pmap_remove:
+ *
+ *     Removes all physical pages in the specified
+ *     object range from all physical maps.
+ *
+ *     The object must *not* be locked.
+ */
+void vm_object_pmap_remove(object, start, end)
+       register vm_object_t    object;
+       register vm_offset_t    start;
+       register vm_offset_t    end;
+{
+       register vm_page_t      p;
+
+       if (object == NULL)
+               return;
+
+       vm_object_lock(object);
+       p = (vm_page_t) queue_first(&object->memq);
+       while (!queue_end(&object->memq, (queue_entry_t) p)) {
+               if ((start <= p->offset) && (p->offset < end))
+                       pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
+               p = (vm_page_t) queue_next(&p->listq);
+       }
+       vm_object_unlock(object);
+}
+
+/*
+ *     vm_object_copy:
+ *
+ *     Create a new object which is a copy of an existing
+ *     object, and mark all of the pages in the existing
+ *     object 'copy-on-write'.  The new object has one reference.
+ *     Returns the new object.
+ *
+ *     May defer the copy until later if the object is not backed
+ *     up by a non-default pager.
+ */
+void vm_object_copy(src_object, src_offset, size,
+                   dst_object, dst_offset, src_needs_copy)
+       register vm_object_t    src_object;
+       vm_offset_t             src_offset;
+       vm_size_t               size;
+       vm_object_t             *dst_object;    /* OUT */
+       vm_offset_t             *dst_offset;    /* OUT */
+       boolean_t               *src_needs_copy;        /* OUT */
+{
+       register vm_object_t    new_copy;
+       register vm_object_t    old_copy;
+       vm_offset_t             new_start, new_end;
+
+       register vm_page_t      p;
+
+       if (src_object == NULL) {
+               /*
+                *      Nothing to copy
+                */
+               *dst_object = NULL;
+               *dst_offset = 0;
+               *src_needs_copy = FALSE;
+               return;
+       }
+
+       /*
+        *      If the object's pager is null_pager or the
+        *      default pager, we don't have to make a copy
+        *      of it.  Instead, we set the needs copy flag and
+        *      make a shadow later.
+        */
+
+       vm_object_lock(src_object);
+       if (src_object->pager == NULL ||
+           src_object->internal) {
+
+               /*
+                *      Make another reference to the object
+                */
+               src_object->ref_count++;
+
+               /*
+                *      Mark all of the pages copy-on-write.
+                */
+               for (p = (vm_page_t) queue_first(&src_object->memq);
+                    !queue_end(&src_object->memq, (queue_entry_t)p);
+                    p = (vm_page_t) queue_next(&p->listq)) {
+                       if (src_offset <= p->offset &&
+                           p->offset < src_offset + size)
+                               p->copy_on_write = TRUE;
+               }
+               vm_object_unlock(src_object);
+
+               *dst_object = src_object;
+               *dst_offset = src_offset;
+               
+               /*
+                *      Must make a shadow when write is desired
+                */
+               *src_needs_copy = TRUE;
+               return;
+       }
+
+       /*
+        *      Try to collapse the object before copying it.
+        */
+       vm_object_collapse(src_object);
+
+       /*
+        *      If the object has a pager, the pager wants to
+        *      see all of the changes.  We need a copy-object
+        *      for the changed pages.
+        *
+        *      If there is a copy-object, and it is empty,
+        *      no changes have been made to the object since the
+        *      copy-object was made.  We can use the same copy-
+        *      object.
+        */
+
+    Retry1:
+       old_copy = src_object->copy;
+       if (old_copy != NULL) {
+               /*
+                *      Try to get the locks (out of order)
+                */
+               if (!vm_object_lock_try(old_copy)) {
+                       vm_object_unlock(src_object);
+
+                       /* should spin a bit here... */
+                       vm_object_lock(src_object);
+                       goto Retry1;
+               }
+
+               if (old_copy->resident_page_count == 0 &&
+                   old_copy->pager == NULL) {
+                       /*
+                        *      Return another reference to
+                        *      the existing copy-object.
+                        */
+                       old_copy->ref_count++;
+                       vm_object_unlock(old_copy);
+                       vm_object_unlock(src_object);
+                       *dst_object = old_copy;
+                       *dst_offset = src_offset;
+                       *src_needs_copy = FALSE;
+                       return;
+               }
+               vm_object_unlock(old_copy);
+       }
+       vm_object_unlock(src_object);
+
+       /*
+        *      If the object has a pager, the pager wants
+        *      to see all of the changes.  We must make
+        *      a copy-object and put the changed pages there.
+        *
+        *      The copy-object is always made large enough to
+        *      completely shadow the original object, since
+        *      it may have several users who want to shadow
+        *      the original object at different points.
+        */
+
+       new_copy = vm_object_allocate(src_object->size);
+
+    Retry2:
+       vm_object_lock(src_object);
+       /*
+        *      Copy object may have changed while we were unlocked
+        */
+       old_copy = src_object->copy;
+       if (old_copy != NULL) {
+               /*
+                *      Try to get the locks (out of order)
+                */
+               if (!vm_object_lock_try(old_copy)) {
+                       vm_object_unlock(src_object);
+                       goto Retry2;
+               }
+
+               /*
+                *      Consistency check
+                */
+               if (old_copy->shadow != src_object ||
+                   old_copy->shadow_offset != (vm_offset_t) 0)
+                       panic("vm_object_copy: copy/shadow inconsistency");
+
+               /*
+                *      Make the old copy-object shadow the new one.
+                *      It will receive no more pages from the original
+                *      object.
+                */
+
+               src_object->ref_count--;        /* remove ref. from old_copy */
+               old_copy->shadow = new_copy;
+               new_copy->ref_count++;          /* locking not needed - we
+                                                  have the only pointer */
+               vm_object_unlock(old_copy);     /* done with old_copy */
+       }
+
+       new_start = (vm_offset_t) 0;    /* always shadow original at 0 */
+       new_end   = (vm_offset_t) new_copy->size; /* for the whole object */
+
+       /*
+        *      Point the new copy at the existing object.
+        */
+
+       new_copy->shadow = src_object;
+       new_copy->shadow_offset = new_start;
+       src_object->ref_count++;
+       src_object->copy = new_copy;
+
+       /*
+        *      Mark all the affected pages of the existing object
+        *      copy-on-write.
+        */
+       p = (vm_page_t) queue_first(&src_object->memq);
+       while (!queue_end(&src_object->memq, (queue_entry_t) p)) {
+               if ((new_start <= p->offset) && (p->offset < new_end))
+                       p->copy_on_write = TRUE;
+               p = (vm_page_t) queue_next(&p->listq);
+       }
+
+       vm_object_unlock(src_object);
+
+       *dst_object = new_copy;
+       *dst_offset = src_offset - new_start;
+       *src_needs_copy = FALSE;
+}
+
+/*
+ *     vm_object_shadow:
+ *
+ *     Create a new object which is backed by the
+ *     specified existing object range.  The source
+ *     object reference is deallocated.
+ *
+ *     The new object and offset into that object
+ *     are returned in the source parameters.
+ */
+
+void vm_object_shadow(object, offset, length)
+       vm_object_t     *object;        /* IN/OUT */
+       vm_offset_t     *offset;        /* IN/OUT */
+       vm_size_t       length;
+{
+       register vm_object_t    source;
+       register vm_object_t    result;
+
+       source = *object;
+
+       /*
+        *      Allocate a new object with the given length
+        */
+
+       if ((result = vm_object_allocate(length)) == NULL)
+               panic("vm_object_shadow: no object for shadowing");
+
+       /*
+        *      The new object shadows the source object, adding
+        *      a reference to it.  Our caller changes his reference
+        *      to point to the new object, removing a reference to
+        *      the source object.  Net result: no change of reference
+        *      count.
+        */
+       result->shadow = source;
+       
+       /*
+        *      Store the offset into the source object,
+        *      and fix up the offset into the new object.
+        */
+
+       result->shadow_offset = *offset;
+
+       /*
+        *      Return the new things
+        */
+
+       *offset = 0;
+       *object = result;
+}
+
+/*
+ *     Set the specified object's pager to the specified pager.
+ */
+
+void vm_object_setpager(object, pager, paging_offset,
+                       read_only)
+       vm_object_t     object;
+       vm_pager_t      pager;
+       vm_offset_t     paging_offset;
+       boolean_t       read_only;
+{
+#ifdef lint
+       read_only++;    /* No longer used */
+#endif lint
+
+       vm_object_lock(object);                 /* XXX ? */
+       object->pager = pager;
+       object->paging_offset = paging_offset;
+       vm_object_unlock(object);                       /* XXX ? */
+}
+
+/*
+ *     vm_object_hash hashes the pager/id pair.
+ */
+
+#define vm_object_hash(pager) \
+       (((unsigned)pager)%VM_OBJECT_HASH_COUNT)
+
+/*
+ *     vm_object_lookup looks in the object cache for an object with the
+ *     specified pager and paging id.
+ */
+
+vm_object_t vm_object_lookup(pager)
+       vm_pager_t      pager;
+{
+       register queue_t                bucket;
+       register vm_object_hash_entry_t entry;
+       vm_object_t                     object;
+
+       bucket = &vm_object_hashtable[vm_object_hash(pager)];
+
+       vm_object_cache_lock();
+
+       entry = (vm_object_hash_entry_t) queue_first(bucket);
+       while (!queue_end(bucket, (queue_entry_t) entry)) {
+               object = entry->object;
+               if (object->pager == pager) {
+                       vm_object_lock(object);
+                       if (object->ref_count == 0) {
+                               queue_remove(&vm_object_cached_list, object,
+                                               vm_object_t, cached_list);
+                               vm_object_cached--;
+                       }
+                       object->ref_count++;
+                       vm_object_unlock(object);
+                       vm_object_cache_unlock();
+                       return(object);
+               }
+               entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
+       }
+
+       vm_object_cache_unlock();
+       return(NULL);
+}
+
+/*
+ *     vm_object_enter enters the specified object/pager/id into
+ *     the hash table.
+ */
+
+void vm_object_enter(object, pager)
+       vm_object_t     object;
+       vm_pager_t      pager;
+{
+       register queue_t                bucket;
+       register vm_object_hash_entry_t entry;
+
+       /*
+        *      We don't cache null objects, and we can't cache
+        *      objects with the null pager.
+        */
+
+       if (object == NULL)
+               return;
+       if (pager == NULL)
+               return;
+
+       bucket = &vm_object_hashtable[vm_object_hash(pager)];
+       entry = (vm_object_hash_entry_t)
+               malloc((u_long)sizeof *entry, M_VMOBJHASH, M_WAITOK);
+       entry->object = object;
+       object->can_persist = TRUE;
+
+       vm_object_cache_lock();
+       queue_enter(bucket, entry, vm_object_hash_entry_t, hash_links);
+       vm_object_cache_unlock();
+}
+
+/*
+ *     vm_object_remove:
+ *
+ *     Remove the pager from the hash table.
+ *     Note:  This assumes that the object cache
+ *     is locked.  XXX this should be fixed
+ *     by reorganizing vm_object_deallocate.
+ */
+vm_object_remove(pager)
+       register vm_pager_t     pager;
+{
+       register queue_t                bucket;
+       register vm_object_hash_entry_t entry;
+       register vm_object_t            object;
+
+       bucket = &vm_object_hashtable[vm_object_hash(pager)];
+
+       entry = (vm_object_hash_entry_t) queue_first(bucket);
+       while (!queue_end(bucket, (queue_entry_t) entry)) {
+               object = entry->object;
+               if (object->pager == pager) {
+                       queue_remove(bucket, entry, vm_object_hash_entry_t,
+                                       hash_links);
+                       free((caddr_t)entry, M_VMOBJHASH);
+                       break;
+               }
+               entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
+       }
+}
+
+/*
+ *     vm_object_cache_clear removes all objects from the cache.
+ *
+ */
+
+void vm_object_cache_clear()
+{
+       register vm_object_t    object;
+
+       /*
+        *      Remove each object in the cache by scanning down the
+        *      list of cached objects.
+        */
+       vm_object_cache_lock();
+       while (!queue_empty(&vm_object_cached_list)) {
+               object = (vm_object_t) queue_first(&vm_object_cached_list);
+               vm_object_cache_unlock();
+
+               /* 
+                * Note: it is important that we use vm_object_lookup
+                * to gain a reference, and not vm_object_reference, because
+                * the logic for removing an object from the cache lies in 
+                * lookup.
+                */
+               if (object != vm_object_lookup(object->pager))
+                       panic("vm_object_cache_clear: I'm sooo confused.");
+               pager_cache(object, FALSE);
+
+               vm_object_cache_lock();
+       }
+       vm_object_cache_unlock();
+}
+
+boolean_t      vm_object_collapse_allowed = TRUE;
+/*
+ *     vm_object_collapse:
+ *
+ *     Collapse an object with the object backing it.
+ *     Pages in the backing object are moved into the
+ *     parent, and the backing object is deallocated.
+ *
+ *     Requires that the object be locked and the page
+ *     queues be unlocked.
+ *
+ */
+void vm_object_collapse(object)
+       register vm_object_t    object;
+
+{
+       register vm_object_t    backing_object;
+       register vm_offset_t    backing_offset;
+       register vm_size_t      size;
+       register vm_offset_t    new_offset;
+       register vm_page_t      p, pp;
+
+       if (!vm_object_collapse_allowed)
+               return;
+
+       while (TRUE) {
+               /*
+                *      Verify that the conditions are right for collapse:
+                *
+                *      The object exists and no pages in it are currently
+                *      being paged out (or have ever been paged out).
+                */
+               if (object == NULL ||
+                   object->paging_in_progress != 0 ||
+                   object->pager != NULL)
+                       return;
+
+               /*
+                *              There is a backing object, and
+                */
+       
+               if ((backing_object = object->shadow) == NULL)
+                       return;
+       
+               vm_object_lock(backing_object);
+               /*
+                *      ...
+                *              The backing object is not read_only,
+                *              and no pages in the backing object are
+                *              currently being paged out.
+                *              The backing object is internal.
+                */
+       
+               if (!backing_object->internal ||
+                   backing_object->paging_in_progress != 0) {
+                       vm_object_unlock(backing_object);
+                       return;
+               }
+       
+               /*
+                *      The backing object can't be a copy-object:
+                *      the shadow_offset for the copy-object must stay
+                *      as 0.  Furthermore (for the 'we have all the
+                *      pages' case), if we bypass backing_object and
+                *      just shadow the next object in the chain, old
+                *      pages from that object would then have to be copied
+                *      BOTH into the (former) backing_object and into the
+                *      parent object.
+                */
+               if (backing_object->shadow != NULL &&
+                   backing_object->shadow->copy != NULL) {
+                       vm_object_unlock(backing_object);
+                       return;
+               }
+
+               /*
+                *      We know that we can either collapse the backing
+                *      object (if the parent is the only reference to
+                *      it) or (perhaps) remove the parent's reference
+                *      to it.
+                */
+
+               backing_offset = object->shadow_offset;
+               size = object->size;
+
+               /*
+                *      If there is exactly one reference to the backing
+                *      object, we can collapse it into the parent.
+                */
+       
+               if (backing_object->ref_count == 1) {
+
+                       /*
+                        *      We can collapse the backing object.
+                        *
+                        *      Move all in-memory pages from backing_object
+                        *      to the parent.  Pages that have been paged out
+                        *      will be overwritten by any of the parent's
+                        *      pages that shadow them.
+                        */
+
+                       while (!queue_empty(&backing_object->memq)) {
+
+                               p = (vm_page_t)
+                                       queue_first(&backing_object->memq);
+
+                               new_offset = (p->offset - backing_offset);
+
+                               /*
+                                *      If the parent has a page here, or if
+                                *      this page falls outside the parent,
+                                *      dispose of it.
+                                *
+                                *      Otherwise, move it as planned.
+                                */
+
+                               if (p->offset < backing_offset ||
+                                   new_offset >= size) {
+                                       vm_page_lock_queues();
+                                       vm_page_free(p);
+                                       vm_page_unlock_queues();
+                               } else {
+                                   pp = vm_page_lookup(object, new_offset);
+                                   if (pp != NULL && !pp->fake) {
+                                       vm_page_lock_queues();
+                                       vm_page_free(p);
+                                       vm_page_unlock_queues();
+                                   }
+                                   else {
+                                       if (pp) {
+                                           /* may be someone waiting for it */
+                                           PAGE_WAKEUP(pp);
+                                           vm_page_lock_queues();
+                                           vm_page_free(pp);
+                                           vm_page_unlock_queues();
+                                       }
+                                       vm_page_rename(p, object, new_offset);
+                                   }
+                               }
+                       }
+
+                       /*
+                        *      Move the pager from backing_object to object.
+                        *
+                        *      XXX We're only using part of the paging space
+                        *      for keeps now... we ought to discard the
+                        *      unused portion.
+                        */
+
+                       object->pager = backing_object->pager;
+                       object->paging_offset += backing_offset;
+
+                       backing_object->pager = NULL;
+
+                       /*
+                        *      Object now shadows whatever backing_object did.
+                        *      Note that the reference to backing_object->shadow
+                        *      moves from within backing_object to within object.
+                        */
+
+                       object->shadow = backing_object->shadow;
+                       object->shadow_offset += backing_object->shadow_offset;
+                       if (object->shadow != NULL &&
+                           object->shadow->copy != NULL) {
+                               panic("vm_object_collapse: we collapsed a copy-object!");
+                       }
+                       /*
+                        *      Discard backing_object.
+                        *
+                        *      Since the backing object has no pages, no
+                        *      pager left, and no object references within it,
+                        *      all that is necessary is to dispose of it.
+                        */
+
+                       vm_object_unlock(backing_object);
+
+                       simple_lock(&vm_object_list_lock);
+                       queue_remove(&vm_object_list, backing_object,
+                                               vm_object_t, object_list);
+                       vm_object_count--;
+                       simple_unlock(&vm_object_list_lock);
+
+                       free((caddr_t)backing_object, M_VMOBJ);
+
+                       object_collapses++;
+               }
+               else {
+                       /*
+                        *      If all of the pages in the backing object are
+                        *      shadowed by the parent object, the parent
+                        *      object no longer has to shadow the backing
+                        *      object; it can shadow the next one in the
+                        *      chain.
+                        *
+                        *      The backing object must not be paged out - we'd
+                        *      have to check all of the paged-out pages, as
+                        *      well.
+                        */
+
+                       if (backing_object->pager != NULL) {
+                               vm_object_unlock(backing_object);
+                               return;
+                       }
+
+                       /*
+                        *      Should have a check for a 'small' number
+                        *      of pages here.
+                        */
+
+                       p = (vm_page_t) queue_first(&backing_object->memq);
+                       while (!queue_end(&backing_object->memq,
+                                         (queue_entry_t) p)) {
+
+                               new_offset = (p->offset - backing_offset);
+
+                               /*
+                                *      If the parent has a page here, or if
+                                *      this page falls outside the parent,
+                                *      keep going.
+                                *
+                                *      Otherwise, the backing_object must be
+                                *      left in the chain.
+                                */
+
+                               if (p->offset >= backing_offset &&
+                                   new_offset <= size &&
+                                   ((pp = vm_page_lookup(object, new_offset))
+                                     == NULL ||
+                                    pp->fake)) {
+                                       /*
+                                        *      Page still needed.
+                                        *      Can't go any further.
+                                        */
+                                       vm_object_unlock(backing_object);
+                                       return;
+                               }
+                               p = (vm_page_t) queue_next(&p->listq);
+                       }
+
+                       /*
+                        *      Make the parent shadow the next object
+                        *      in the chain.  Deallocating backing_object
+                        *      will not remove it, since its reference
+                        *      count is at least 2.
+                        */
+
+                       vm_object_reference(object->shadow = backing_object->shadow);
+                       object->shadow_offset += backing_object->shadow_offset;
+
+                       /*      Drop the reference count on backing_object.
+                        *      Since its ref_count was at least 2, it
+                        *      will not vanish; so we don't need to call
+                        *      vm_object_deallocate.
+                        */
+                       backing_object->ref_count--;
+                       vm_object_unlock(backing_object);
+
+                       object_bypasses ++;
+
+               }
+
+               /*
+                *      Try again with this object's new backing object.
+                */
+       }
+}
+
+/*
+ *     vm_object_page_remove: [internal]
+ *
+ *     Removes all physical pages in the specified
+ *     object range from the object's list of pages.
+ *
+ *     The object must be locked.
+ */
+void vm_object_page_remove(object, start, end)
+       register vm_object_t    object;
+       register vm_offset_t    start;
+       register vm_offset_t    end;
+{
+       register vm_page_t      p, next;
+
+       if (object == NULL)
+               return;
+
+       p = (vm_page_t) queue_first(&object->memq);
+       while (!queue_end(&object->memq, (queue_entry_t) p)) {
+               next = (vm_page_t) queue_next(&p->listq);
+               if ((start <= p->offset) && (p->offset < end)) {
+                       pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
+                       vm_page_lock_queues();
+                       vm_page_free(p);
+                       vm_page_unlock_queues();
+               }
+               p = next;
+       }
+}
+
+/*
+ *     Routine:        vm_object_coalesce
+ *     Function:       Coalesces two objects backing up adjoining
+ *                     regions of memory into a single object.
+ *
+ *     returns TRUE if objects were combined.
+ *
+ *     NOTE:   Only works at the moment if the second object is NULL -
+ *             if it's not, which object do we lock first?
+ *
+ *     Parameters:
+ *             prev_object     First object to coalesce
+ *             prev_offset     Offset into prev_object
+ *             next_object     Second object into coalesce
+ *             next_offset     Offset into next_object
+ *
+ *             prev_size       Size of reference to prev_object
+ *             next_size       Size of reference to next_object
+ *
+ *     Conditions:
+ *     The object must *not* be locked.
+ */
+boolean_t vm_object_coalesce(prev_object, next_object,
+                       prev_offset, next_offset,
+                       prev_size, next_size)
+
+       register vm_object_t    prev_object;
+       vm_object_t     next_object;
+       vm_offset_t     prev_offset, next_offset;
+       vm_size_t       prev_size, next_size;
+{
+       vm_size_t       newsize;
+
+#ifdef lint
+       next_offset++;
+#endif lint
+
+       if (next_object != NULL) {
+               return(FALSE);
+       }
+
+       if (prev_object == NULL) {
+               return(TRUE);
+       }
+
+       vm_object_lock(prev_object);
+
+       /*
+        *      Try to collapse the object first
+        */
+       vm_object_collapse(prev_object);
+
+       /*
+        *      Can't coalesce if:
+        *      . more than one reference
+        *      . paged out
+        *      . shadows another object
+        *      . has a copy elsewhere
+        *      (any of which mean that the pages not mapped to
+        *      prev_entry may be in use anyway)
+        */
+
+       if (prev_object->ref_count > 1 ||
+               prev_object->pager != NULL ||
+               prev_object->shadow != NULL ||
+               prev_object->copy != NULL) {
+               vm_object_unlock(prev_object);
+               return(FALSE);
+       }
+
+       /*
+        *      Remove any pages that may still be in the object from
+        *      a previous deallocation.
+        */
+
+       vm_object_page_remove(prev_object,
+                       prev_offset + prev_size,
+                       prev_offset + prev_size + next_size);
+
+       /*
+        *      Extend the object if necessary.
+        */
+       newsize = prev_offset + prev_size + next_size;
+       if (newsize > prev_object->size)
+               prev_object->size = newsize;
+
+       vm_object_unlock(prev_object);
+       return(TRUE);
+}
+
+/*
+ *     vm_object_print:        [ debug ]
+ */
+void vm_object_print(object, full)
+       vm_object_t     object;
+       boolean_t       full;
+{
+       register vm_page_t      p;
+       extern indent;
+
+       register int count;
+
+       if (object == NULL)
+               return;
+
+       iprintf("Object 0x%x: size=0x%x, res=%d, ref=%d, ",
+               (int) object, (int) object->size,
+               object->resident_page_count, object->ref_count);
+       printf("pager=0x%x+0x%x, shadow=(0x%x)+0x%x\n",
+              (int) object->pager, (int) object->paging_offset,
+              (int) object->shadow, (int) object->shadow_offset);
+       printf("cache: next=0x%x, prev=0x%x\n",
+              object->cached_list.next, object->cached_list.prev);
+
+       if (!full)
+               return;
+
+       indent += 2;
+       count = 0;
+       p = (vm_page_t) queue_first(&object->memq);
+       while (!queue_end(&object->memq, (queue_entry_t) p)) {
+               if (count == 0)
+                       iprintf("memory:=");
+               else if (count == 6) {
+                       printf("\n");
+                       iprintf(" ...");
+                       count = 0;
+               } else
+                       printf(",");
+               count++;
+
+               printf("(off=0x%x,page=0x%x)", p->offset, VM_PAGE_TO_PHYS(p));
+               p = (vm_page_t) queue_next(&p->listq);
+       }
+       if (count != 0)
+               printf("\n");
+       indent -= 2;
+}
diff --git a/usr/src/sys.386bsd/vm/vm_object.h b/usr/src/sys.386bsd/vm/vm_object.h
new file mode 100644 (file)
index 0000000..f024f8e
--- /dev/null
@@ -0,0 +1,171 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_object.h 7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Virtual memory object module definitions.
+ */
+
+#ifndef        _VM_OBJECT_
+#define        _VM_OBJECT_
+
+#include <vm/vm_pager.h>
+
+/*
+ *     Types defined:
+ *
+ *     vm_object_t             Virtual memory object.
+ */
+
+struct vm_object {
+       queue_chain_t           memq;           /* Resident memory */
+       queue_chain_t           object_list;    /* list of all objects */
+       simple_lock_data_t      Lock;           /* Synchronization */
+       int                     LockHolder;
+       int                     ref_count;      /* How many refs?? */
+       vm_size_t               size;           /* Object size */
+       int                     resident_page_count;
+                                               /* number of resident pages */
+       struct vm_object        *copy;          /* Object that holds copies of
+                                                  my changed pages */
+       vm_pager_t              pager;          /* Where to get data */
+       boolean_t               pager_ready;    /* Have pager fields been filled? */
+       vm_offset_t             paging_offset;  /* Offset into paging space */
+       struct vm_object        *shadow;        /* My shadow */
+       vm_offset_t             shadow_offset;  /* Offset in shadow */
+       unsigned int
+                               paging_in_progress:16,
+                                               /* Paging (in or out) - don't
+                                                  collapse or destroy */
+       /* boolean_t */         can_persist:1,  /* allow to persist */
+       /* boolean_t */         internal:1;     /* internally created object */
+       queue_chain_t           cached_list;    /* for persistence */
+};
+
+typedef struct vm_object       *vm_object_t;
+
+struct vm_object_hash_entry {
+       queue_chain_t           hash_links;     /* hash chain links */
+       vm_object_t             object;         /* object we represent */
+};
+
+typedef struct vm_object_hash_entry    *vm_object_hash_entry_t;
+
+#ifdef KERNEL
+queue_head_t   vm_object_cached_list;  /* list of objects persisting */
+int            vm_object_cached;       /* size of cached list */
+simple_lock_data_t     vm_cache_lock;  /* lock for object cache */
+
+queue_head_t   vm_object_list;         /* list of allocated objects */
+long           vm_object_count;        /* count of all objects */
+simple_lock_data_t     vm_object_list_lock;
+                                       /* lock for object list and count */
+
+vm_object_t    kernel_object;          /* the single kernel object */
+vm_object_t    kmem_object;
+
+#define        vm_object_cache_lock()          simple_lock(&vm_cache_lock)
+#define        vm_object_cache_unlock()        simple_unlock(&vm_cache_lock)
+#endif KERNEL
+
+/*
+ *     Declare procedures that operate on VM objects.
+ */
+
+void           vm_object_init ();
+void           vm_object_terminate();
+vm_object_t    vm_object_allocate();
+void           vm_object_reference();
+void           vm_object_deallocate();
+void           vm_object_pmap_copy();
+void           vm_object_pmap_remove();
+void           vm_object_page_remove();
+void           vm_object_shadow();
+void           vm_object_copy();
+void           vm_object_collapse();
+vm_object_t    vm_object_lookup();
+void           vm_object_enter();
+void           vm_object_setpager();
+#define                vm_object_cache(pager)          pager_cache(vm_object_lookup(pager),TRUE)
+#define                vm_object_uncache(pager)        pager_cache(vm_object_lookup(pager),FALSE)
+
+void           vm_object_cache_clear();
+void           vm_object_print();
+
+#if    VM_OBJECT_DEBUG
+#define        vm_object_lock_init(object)     { simple_lock_init(&(object)->Lock); (object)->LockHolder = 0; }
+#define        vm_object_lock(object)          { simple_lock(&(object)->Lock); (object)->LockHolder = (int) current_thread(); }
+#define        vm_object_unlock(object)        { (object)->LockHolder = 0; simple_unlock(&(object)->Lock); }
+#define        vm_object_lock_try(object)      (simple_lock_try(&(object)->Lock) ? ( ((object)->LockHolder = (int) current_thread()) , TRUE) : FALSE)
+#define        vm_object_sleep(event, object, interruptible) \
+                                       { (object)->LockHolder = 0; thread_sleep((event), &(object)->Lock, (interruptible)); }
+#else  VM_OBJECT_DEBUG
+#define        vm_object_lock_init(object)     simple_lock_init(&(object)->Lock)
+#define        vm_object_lock(object)          simple_lock(&(object)->Lock)
+#define        vm_object_unlock(object)        simple_unlock(&(object)->Lock)
+#define        vm_object_lock_try(object)      simple_lock_try(&(object)->Lock)
+#define        vm_object_sleep(event, object, interruptible) \
+                                       thread_sleep((event), &(object)->Lock, (interruptible))
+#endif VM_OBJECT_DEBUG
+
+#endif _VM_OBJECT_
diff --git a/usr/src/sys.386bsd/vm/vm_page.h b/usr/src/sys.386bsd/vm/vm_page.h
new file mode 100644 (file)
index 0000000..45aa618
--- /dev/null
@@ -0,0 +1,261 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_page.h   7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Resident memory system definitions.
+ */
+
+#ifndef        _VM_PAGE_
+#define        _VM_PAGE_
+
+/*
+ *     Management of resident (logical) pages.
+ *
+ *     A small structure is kept for each resident
+ *     page, indexed by page number.  Each structure
+ *     is an element of several lists:
+ *
+ *             A hash table bucket used to quickly
+ *             perform object/offset lookups
+ *
+ *             A list of all pages for a given object,
+ *             so they can be quickly deactivated at
+ *             time of deallocation.
+ *
+ *             An ordered list of pages due for pageout.
+ *
+ *     In addition, the structure contains the object
+ *     and offset to which this page belongs (for pageout),
+ *     and sundry status bits.
+ *
+ *     Fields in this structure are locked either by the lock on the
+ *     object that the page belongs to (O) or by the lock on the page
+ *     queues (P).
+ */
+
+struct vm_page {
+       queue_chain_t   pageq;          /* queue info for FIFO
+                                        * queue or free list (P) */
+       queue_chain_t   hashq;          /* hash table links (O)*/
+       queue_chain_t   listq;          /* all pages in same object (O)*/
+
+       vm_object_t     object;         /* which object am I in (O,P)*/
+       vm_offset_t     offset;         /* offset into that object (O,P) */
+
+       unsigned int    wire_count:16,  /* how many wired down maps use me?
+                                          (P) */
+       /* boolean_t */ inactive:1,     /* page is in inactive list (P) */
+                       active:1,       /* page is in active list (P) */
+                       laundry:1,      /* page is being cleaned now (P)*/
+#ifdef DEBUG
+                       pagerowned:1,   /* async paging op in progress */
+                       ptpage:1,       /* is a user page table page */
+#endif
+                       :0;             /* (force to 'long' boundary) */
+#ifdef ns32000
+       int             pad;            /* extra space for ns32000 bit ops */
+#endif ns32000
+       boolean_t       clean;          /* page has not been modified */
+       unsigned int
+       /* boolean_t */ busy:1,         /* page is in transit (O) */
+                       wanted:1,       /* someone is waiting for page (O) */
+                       tabled:1,       /* page is in VP table (O) */
+                       copy_on_write:1,/* page must be copied before being
+                                          changed (O) */
+                       fictitious:1,   /* physical page doesn't exist (O) */
+                       absent:1,       /* virtual page doesn't exist (O) */
+                       fake:1,         /* page is a placeholder for page-in
+                                          (O) */
+                       :0;
+
+       vm_offset_t     phys_addr;      /* physical address of page */
+       vm_prot_t       page_lock;      /* Uses prohibited by data manager */
+       vm_prot_t       unlock_request; /* Outstanding unlock request */
+};
+
+typedef struct vm_page *vm_page_t;
+
+#if    VM_PAGE_DEBUG
+#define        VM_PAGE_CHECK(mem) { \
+               if ( (((unsigned int) mem) < ((unsigned int) &vm_page_array[0])) || \
+                    (((unsigned int) mem) > ((unsigned int) &vm_page_array[last_page-first_page])) || \
+                    (mem->active && mem->inactive) \
+                   ) panic("vm_page_check: not valid!"); \
+               }
+#else  VM_PAGE_DEBUG
+#define        VM_PAGE_CHECK(mem)
+#endif VM_PAGE_DEBUG
+
+#ifdef KERNEL
+/*
+ *     Each pageable resident page falls into one of three lists:
+ *
+ *     free    
+ *             Available for allocation now.
+ *     inactive
+ *             Not referenced in any map, but still has an
+ *             object/offset-page mapping, and may be dirty.
+ *             This is the list of pages that should be
+ *             paged out next.
+ *     active
+ *             A list of pages which have been placed in
+ *             at least one physical map.  This list is
+ *             ordered, in LRU-like fashion.
+ */
+
+extern
+queue_head_t   vm_page_queue_free;     /* memory free queue */
+extern
+queue_head_t   vm_page_queue_active;   /* active memory queue */
+extern
+queue_head_t   vm_page_queue_inactive; /* inactive memory queue */
+
+extern
+vm_page_t      vm_page_array;          /* First resident page in table */
+extern
+long           first_page;             /* first physical page number */
+                                       /* ... represented in vm_page_array */
+extern
+long           last_page;              /* last physical page number */
+                                       /* ... represented in vm_page_array */
+                                       /* [INCLUSIVE] */
+extern
+vm_offset_t    first_phys_addr;        /* physical address for first_page */
+extern
+vm_offset_t    last_phys_addr;         /* physical address for last_page */
+
+extern
+int    vm_page_free_count;     /* How many pages are free? */
+extern
+int    vm_page_active_count;   /* How many pages are active? */
+extern
+int    vm_page_inactive_count; /* How many pages are inactive? */
+extern
+int    vm_page_wire_count;     /* How many pages are wired? */
+extern
+int    vm_page_free_target;    /* How many do we want free? */
+extern
+int    vm_page_free_min;       /* When to wakeup pageout */
+extern
+int    vm_page_inactive_target;/* How many do we want inactive? */
+extern
+int    vm_page_free_reserved;  /* How many pages reserved to do pageout */
+extern
+int    vm_page_laundry_count;  /* How many pages being laundered? */
+
+#define VM_PAGE_TO_PHYS(entry) ((entry)->phys_addr)
+
+#define IS_VM_PHYSADDR(pa) \
+               ((pa) >= first_phys_addr && (pa) <= last_phys_addr)
+
+#define PHYS_TO_VM_PAGE(pa) \
+               (&vm_page_array[atop(pa) - first_page ])
+
+extern
+simple_lock_data_t     vm_page_queue_lock;     /* lock on active and inactive
+                                                  page queues */
+extern
+simple_lock_data_t     vm_page_queue_free_lock;
+                                               /* lock on free page queue */
+vm_offset_t    vm_page_startup();
+vm_page_t      vm_page_lookup();
+vm_page_t      vm_page_alloc();
+void           vm_page_init();
+void           vm_page_free();
+void           vm_page_activate();
+void           vm_page_deactivate();
+void           vm_page_rename();
+void           vm_page_replace();
+
+boolean_t      vm_page_zero_fill();
+void           vm_page_copy();
+
+void           vm_page_wire();
+void           vm_page_unwire();
+
+void           vm_set_page_size();
+
+/*
+ *     Functions implemented as macros
+ */
+
+#define PAGE_ASSERT_WAIT(m, interruptible)     { \
+                               (m)->wanted = TRUE; \
+                               assert_wait((int) (m), (interruptible)); \
+                       }
+
+#define PAGE_WAKEUP(m) { \
+                               (m)->busy = FALSE; \
+                               if ((m)->wanted) { \
+                                       (m)->wanted = FALSE; \
+                                       thread_wakeup((int) (m)); \
+                               } \
+                       }
+
+#define        vm_page_lock_queues()   simple_lock(&vm_page_queue_lock)
+#define        vm_page_unlock_queues() simple_unlock(&vm_page_queue_lock)
+
+#define vm_page_set_modified(m)        { (m)->clean = FALSE; }
+#endif KERNEL
+#endif _VM_PAGE_
diff --git a/usr/src/sys.386bsd/vm/vm_pageout.c b/usr/src/sys.386bsd/vm/vm_pageout.c
new file mode 100644 (file)
index 0000000..5270ae3
--- /dev/null
@@ -0,0 +1,387 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_pageout.c        7.4 (Berkeley) 5/7/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     The proverbial page-out daemon.
+ */
+
+#include "param.h"
+
+#include "vm.h"
+#include "vm_page.h"
+#include "vm_pageout.h"
+
+int    vm_pages_needed;                /* Event on which pageout daemon sleeps */
+int    vm_pageout_free_min = 0;        /* Stop pageout to wait for pagers at this free level */
+
+int    vm_page_free_min_sanity = 40;
+
+/*
+ *     vm_pageout_scan does the dirty work for the pageout daemon.
+ */
+vm_pageout_scan()
+{
+       register vm_page_t      m;
+       register int            page_shortage;
+       register int            s;
+       register int            pages_freed;
+       int                     free;
+
+       /*
+        *      Only continue when we want more pages to be "free"
+        */
+
+       s = splimp();
+       simple_lock(&vm_page_queue_free_lock);
+       free = vm_page_free_count;
+       simple_unlock(&vm_page_queue_free_lock);
+       splx(s);
+
+       if (free < vm_page_free_target) {
+               swapout_threads();
+
+               /*
+                *      Be sure the pmap system is updated so
+                *      we can scan the inactive queue.
+                */
+
+               pmap_update();
+       }
+
+       /*
+        *      Acquire the resident page system lock,
+        *      as we may be changing what's resident quite a bit.
+        */
+       vm_page_lock_queues();
+
+       /*
+        *      Start scanning the inactive queue for pages we can free.
+        *      We keep scanning until we have enough free pages or
+        *      we have scanned through the entire queue.  If we
+        *      encounter dirty pages, we start cleaning them.
+        */
+
+       pages_freed = 0;
+       m = (vm_page_t) queue_first(&vm_page_queue_inactive);
+       while (!queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) {
+               vm_page_t       next;
+
+               s = splimp();
+               simple_lock(&vm_page_queue_free_lock);
+               free = vm_page_free_count;
+               simple_unlock(&vm_page_queue_free_lock);
+               splx(s);
+
+               if (free >= vm_page_free_target)
+                       break;
+
+               if (m->clean) {
+                       next = (vm_page_t) queue_next(&m->pageq);
+                       if (pmap_is_referenced(VM_PAGE_TO_PHYS(m))) {
+                               vm_page_activate(m);
+                               vm_stat.reactivations++;
+                       }
+                       else {
+                               register vm_object_t    object;
+                               object = m->object;
+                               if (!vm_object_lock_try(object)) {
+                                       /*
+                                        *      Can't lock object -
+                                        *      skip page.
+                                        */
+                                       m = next;
+                                       continue;
+                               }
+                               pmap_page_protect(VM_PAGE_TO_PHYS(m),
+                                                 VM_PROT_NONE);
+                               vm_page_free(m);        /* will dequeue */
+                               pages_freed++;
+                               vm_object_unlock(object);
+                       }
+                       m = next;
+               }
+               else {
+                       /*
+                        *      If a page is dirty, then it is either
+                        *      being washed (but not yet cleaned)
+                        *      or it is still in the laundry.  If it is
+                        *      still in the laundry, then we start the
+                        *      cleaning operation.
+                        */
+
+                       if (m->laundry) {
+                               /*
+                                *      Clean the page and remove it from the
+                                *      laundry.
+                                *
+                                *      We set the busy bit to cause
+                                *      potential page faults on this page to
+                                *      block.
+                                *
+                                *      And we set pageout-in-progress to keep
+                                *      the object from disappearing during
+                                *      pageout.  This guarantees that the
+                                *      page won't move from the inactive
+                                *      queue.  (However, any other page on
+                                *      the inactive queue may move!)
+                                */
+
+                               register vm_object_t    object;
+                               register vm_pager_t     pager;
+                               int                     pageout_status;
+
+                               object = m->object;
+                               if (!vm_object_lock_try(object)) {
+                                       /*
+                                        *      Skip page if we can't lock
+                                        *      its object
+                                        */
+                                       m = (vm_page_t) queue_next(&m->pageq);
+                                       continue;
+                               }
+
+                               pmap_page_protect(VM_PAGE_TO_PHYS(m),
+                                                 VM_PROT_NONE);
+                               m->busy = TRUE;
+                               vm_stat.pageouts++;
+
+                               /*
+                                *      Try to collapse the object before
+                                *      making a pager for it.  We must
+                                *      unlock the page queues first.
+                                */
+                               vm_page_unlock_queues();
+
+                               vm_object_collapse(object);
+
+                               object->paging_in_progress++;
+                               vm_object_unlock(object);
+
+                               /*
+                                *      Do a wakeup here in case the following
+                                *      operations block.
+                                */
+                               thread_wakeup((int) &vm_page_free_count);
+
+                               /*
+                                *      If there is no pager for the page,
+                                *      use the default pager.  If there's
+                                *      no place to put the page at the
+                                *      moment, leave it in the laundry and
+                                *      hope that there will be paging space
+                                *      later.
+                                */
+
+                               if ((pager = object->pager) == NULL) {
+                                       pager = vm_pager_allocate(PG_DFLT,
+                                                                 (caddr_t)0,
+                                                                 object->size,
+                                                                 VM_PROT_ALL);
+                                       if (pager != NULL) {
+                                               vm_object_setpager(object,
+                                                       pager, 0, FALSE);
+                                       }
+                               }
+                               pageout_status = pager ?
+                                       vm_pager_put(pager, m, FALSE) :
+                                       VM_PAGER_FAIL;
+                               vm_object_lock(object);
+                               vm_page_lock_queues();
+                               next = (vm_page_t) queue_next(&m->pageq);
+
+                               switch (pageout_status) {
+                               case VM_PAGER_OK:
+                               case VM_PAGER_PEND:
+                                       m->laundry = FALSE;
+                                       break;
+                               case VM_PAGER_BAD:
+                                       /*
+                                        * Page outside of range of object.
+                                        * Right now we essentially lose the
+                                        * changes by pretending it worked.
+                                        * XXX dubious, what should we do?
+                                        */
+                                       m->laundry = FALSE;
+                                       m->clean = TRUE;
+                                       pmap_clear_modify(VM_PAGE_TO_PHYS(m));
+                                       break;
+                               case VM_PAGER_FAIL:
+                                       /*
+                                        * If page couldn't be paged out, then
+                                        * reactivate the page so it doesn't
+                                        * clog the inactive list.  (We will
+                                        * try paging out it again later).
+                                        */
+                                       vm_page_activate(m);
+                                       break;
+                               }
+
+                               pmap_clear_reference(VM_PAGE_TO_PHYS(m));
+
+                               /*
+                                * If the operation is still going, leave
+                                * the page busy to block all other accesses.
+                                * Also, leave the paging in progress
+                                * indicator set so that we don't attempt an
+                                * object collapse.
+                                */
+                               if (pageout_status != VM_PAGER_PEND) {
+                                       m->busy = FALSE;
+                                       PAGE_WAKEUP(m);
+                                       object->paging_in_progress--;
+                               }
+                               thread_wakeup((int) object);
+                               vm_object_unlock(object);
+                               m = next;
+                       }
+                       else
+                               m = (vm_page_t) queue_next(&m->pageq);
+               }
+       }
+       
+       /*
+        *      Compute the page shortage.  If we are still very low on memory
+        *      be sure that we will move a minimal amount of pages from active
+        *      to inactive.
+        */
+
+       page_shortage = vm_page_inactive_target - vm_page_inactive_count;
+       page_shortage -= vm_page_free_count;
+
+       if ((page_shortage <= 0) && (pages_freed == 0))
+               page_shortage = 1;
+
+       while (page_shortage > 0) {
+               /*
+                *      Move some more pages from active to inactive.
+                */
+
+               if (queue_empty(&vm_page_queue_active)) {
+                       break;
+               }
+               m = (vm_page_t) queue_first(&vm_page_queue_active);
+               vm_page_deactivate(m);
+               page_shortage--;
+       }
+
+       vm_page_unlock_queues();
+}
+
+/*
+ *     vm_pageout is the high level pageout daemon.
+ */
+
+void vm_pageout()
+{
+       (void) spl0();
+
+       /*
+        *      Initialize some paging parameters.
+        */
+
+       if (vm_page_free_min == 0) {
+               vm_page_free_min = vm_page_free_count / 20;
+               if (vm_page_free_min < 3)
+                       vm_page_free_min = 3;
+
+               if (vm_page_free_min > vm_page_free_min_sanity)
+                       vm_page_free_min = vm_page_free_min_sanity;
+       }
+
+       if (vm_page_free_reserved == 0) {
+               if ((vm_page_free_reserved = vm_page_free_min / 2) < 10)
+                       vm_page_free_reserved = 10;
+       }
+       if (vm_pageout_free_min == 0) {
+               if ((vm_pageout_free_min = vm_page_free_reserved / 2) > 10)
+                       vm_pageout_free_min = 10;
+       }
+
+       if (vm_page_free_target == 0)
+               vm_page_free_target = (vm_page_free_min * 4) / 3;
+
+       if (vm_page_inactive_target == 0)
+               vm_page_inactive_target = vm_page_free_min * 2;
+
+       if (vm_page_free_target <= vm_page_free_min)
+               vm_page_free_target = vm_page_free_min + 1;
+
+       if (vm_page_inactive_target <= vm_page_free_target)
+               vm_page_inactive_target = vm_page_free_target + 1;
+
+       /*
+        *      The pageout daemon is never done, so loop
+        *      forever.
+        */
+
+       simple_lock(&vm_pages_needed_lock);
+       while (TRUE) {
+               thread_sleep((int) &vm_pages_needed, &vm_pages_needed_lock,
+                            FALSE);
+               vm_pageout_scan();
+               vm_pager_sync();
+               simple_lock(&vm_pages_needed_lock);
+               thread_wakeup((int) &vm_page_free_count);
+       }
+}
diff --git a/usr/src/sys.386bsd/vm/vm_pageout.h b/usr/src/sys.386bsd/vm/vm_pageout.h
new file mode 100644 (file)
index 0000000..3f63f75
--- /dev/null
@@ -0,0 +1,90 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_pageout.h        7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Avadis Tevanian, Jr.
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Header file for pageout daemon.
+ */
+
+/*
+ *     Exported data structures.
+ */
+
+extern int     vm_pages_needed;        /* should be some "event" structure */
+simple_lock_data_t     vm_pages_needed_lock;
+
+
+/*
+ *     Exported routines.
+ */
+
+/*
+ *     Signal pageout-daemon and wait for it.
+ */
+
+#define        VM_WAIT         { \
+                       simple_lock(&vm_pages_needed_lock); \
+                       thread_wakeup((int)&vm_pages_needed); \
+                       thread_sleep((int)&vm_page_free_count, \
+                               &vm_pages_needed_lock, FALSE); \
+                       }
diff --git a/usr/src/sys.386bsd/vm/vm_pager.c b/usr/src/sys.386bsd/vm/vm_pager.c
new file mode 100644 (file)
index 0000000..c221334
--- /dev/null
@@ -0,0 +1,282 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_pager.c  7.4 (Berkeley) 5/7/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Paging space routine stubs.  Emulates a matchmaker-like interface
+ *     for builtin pagers.
+ */
+
+#include "param.h"
+#include "malloc.h"
+
+#include "vm.h"
+#include "vm_page.h"
+#include "vm_kern.h"
+
+#include "swappager.h"
+
+#if NSWAPPAGER > 0
+extern struct pagerops swappagerops;
+#else
+#define        swappagerops    NULL
+#endif
+#include "vnodepager.h"
+#if NVNODEPAGER > 0
+extern struct pagerops vnodepagerops;
+#else
+#define        vnodepagerops   NULL
+#endif
+#include "devpager.h"
+#if NDEVPAGER > 0
+extern struct pagerops devicepagerops;
+#else
+#define        devicepagerops  NULL
+#endif
+
+struct pagerops *pagertab[] = {
+       &swappagerops,          /* PG_SWAP */
+       &vnodepagerops,         /* PG_VNODE */
+       &devicepagerops,        /* PG_DEV */
+};
+int npagers = sizeof (pagertab) / sizeof (pagertab[0]);
+
+struct pagerops *dfltpagerops = NULL;  /* default pager */
+
+/*
+ * Kernel address space for mapping pages.
+ * Used by pagers where KVAs are needed for IO.
+ */
+#define PAGER_MAP_SIZE (256 * PAGE_SIZE)
+vm_map_t pager_map;
+vm_offset_t pager_sva, pager_eva;
+
+void
+vm_pager_init()
+{
+       struct pagerops **pgops;
+
+       /*
+        * Allocate a kernel submap for tracking get/put page mappings
+        */
+       pager_map = kmem_suballoc(kernel_map, &pager_sva, &pager_eva,
+                                 PAGER_MAP_SIZE, FALSE);
+       /*
+        * Initialize known pagers
+        */
+       for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
+               (*(*pgops)->pgo_init)();
+       if (dfltpagerops == NULL)
+               panic("no default pager");
+}
+
+/*
+ * Allocate an instance of a pager of the given type.
+ */
+vm_pager_t
+vm_pager_allocate(type, handle, size, prot)
+       int type;
+       caddr_t handle;
+       vm_size_t size;
+       vm_prot_t prot;
+{
+       vm_pager_t pager;
+       struct pagerops *ops;
+
+       ops = (type == PG_DFLT) ? dfltpagerops : pagertab[type];
+       return((*ops->pgo_alloc)(handle, size, prot));
+}
+
+void
+vm_pager_deallocate(pager)
+       vm_pager_t      pager;
+{
+       if (pager == NULL)
+               panic("vm_pager_deallocate: null pager");
+
+       VM_PAGER_DEALLOC(pager);
+}
+
+vm_pager_get(pager, m, sync)
+       vm_pager_t      pager;
+       vm_page_t       m;
+       boolean_t       sync;
+{
+       extern boolean_t vm_page_zero_fill();
+
+       if (pager == NULL)
+               return(vm_page_zero_fill(m) ? VM_PAGER_OK : VM_PAGER_FAIL);
+       return(VM_PAGER_GET(pager, m, sync));
+}
+
+vm_pager_put(pager, m, sync)
+       vm_pager_t      pager;
+       vm_page_t       m;
+       boolean_t       sync;
+{
+       if (pager == NULL)
+               panic("vm_pager_put: null pager");
+       return(VM_PAGER_PUT(pager, m, sync));
+}
+
+boolean_t
+vm_pager_has_page(pager, offset)
+       vm_pager_t      pager;
+       vm_offset_t     offset;
+{
+       if (pager == NULL)
+               panic("vm_pager_has_page");
+       return(VM_PAGER_HASPAGE(pager, offset));
+}
+
+/*
+ * Called by pageout daemon before going back to sleep.
+ * Gives pagers a chance to clean up any completed async pageing operations.
+ */
+void
+vm_pager_sync()
+{
+       struct pagerops **pgops;
+
+       for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
+               (*(*pgops)->pgo_putpage)(NULL, NULL, FALSE);
+}
+
+vm_offset_t
+vm_pager_map_page(m)
+       vm_page_t       m;
+{
+       vm_offset_t kva;
+
+#ifdef DEBUG
+       if (!m->busy || m->active)
+               panic("vm_pager_map_page: page active or not busy");
+       if (m->pagerowned)
+               printf("vm_pager_map_page: page %x already in pager\n", m);
+#endif
+       kva = kmem_alloc_wait(pager_map, PAGE_SIZE);
+#ifdef DEBUG
+       m->pagerowned = 1;
+#endif
+       pmap_enter(vm_map_pmap(pager_map), kva, VM_PAGE_TO_PHYS(m),
+                  VM_PROT_DEFAULT, TRUE);
+       return(kva);
+}
+
+void
+vm_pager_unmap_page(kva)
+       vm_offset_t     kva;
+{
+#ifdef DEBUG
+       vm_page_t m;
+
+       m = PHYS_TO_VM_PAGE(pmap_extract(vm_map_pmap(pager_map), kva));
+#endif
+       pmap_remove(vm_map_pmap(pager_map), kva, kva + PAGE_SIZE);
+       kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
+#ifdef DEBUG
+       if (m->pagerowned)
+               m->pagerowned = 0;
+       else
+               printf("vm_pager_unmap_page: page %x(%x/%x) not owned\n",
+                      m, kva, VM_PAGE_TO_PHYS(m));
+#endif
+}
+
+vm_pager_t
+vm_pager_lookup(list, handle)
+       register queue_head_t *list;
+       caddr_t handle;
+{
+       register vm_pager_t pager;
+
+       pager = (vm_pager_t) queue_first(list);
+       while (!queue_end(list, (queue_entry_t)pager)) {
+               if (pager->pg_handle == handle)
+                       return(pager);
+               pager = (vm_pager_t) queue_next(&pager->pg_list);
+       }
+       return(NULL);
+}
+
+/*
+ * This routine gains a reference to the object.
+ * Explicit deallocation is necessary.
+ */
+pager_cache(object, should_cache)
+       vm_object_t     object;
+       boolean_t       should_cache;
+{
+       if (object == NULL)
+               return(KERN_INVALID_ARGUMENT);
+
+       vm_object_cache_lock();
+       vm_object_lock(object);
+       object->can_persist = should_cache;
+       vm_object_unlock(object);
+       vm_object_cache_unlock();
+
+       vm_object_deallocate(object);
+
+       return(KERN_SUCCESS);
+}
diff --git a/usr/src/sys.386bsd/vm/vm_pager.h b/usr/src/sys.386bsd/vm/vm_pager.h
new file mode 100644 (file)
index 0000000..e3e0880
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1990 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_pager.h  7.2 (Berkeley) 4/20/91
+ */
+
+/*
+ * Pager routine interface definition.
+ * For BSD we use a cleaner version of the internal pager interface.
+ */
+
+#ifndef        _VM_PAGER_
+#define        _VM_PAGER_
+
+struct pager_struct {
+       queue_head_t    pg_list;        /* links for list management */
+       caddr_t         pg_handle;      /* external handle (vp, dev, fp) */
+       int             pg_type;        /* type of pager */
+       struct pagerops *pg_ops;        /* pager operations */
+       caddr_t         pg_data;        /* private pager data */
+};
+typedef        struct pager_struct *vm_pager_t;
+
+/* pager types */
+#define PG_DFLT                -1
+#define        PG_SWAP         0
+#define        PG_VNODE        1
+#define PG_DEVICE      2
+
+struct pagerops {
+       void            (*pgo_init)();          /* initialize pager */
+       vm_pager_t      (*pgo_alloc)();         /* allocate pager */
+       void            (*pgo_dealloc)();       /* disassociate */
+       int             (*pgo_getpage)();       /* get (read) page */
+       int             (*pgo_putpage)();       /* put (write) page */
+       boolean_t       (*pgo_haspage)();       /* does pager have page? */
+};
+
+/*
+ * get/put return values
+ * OK  operation was successful
+ * BAD specified data was out of the accepted range
+ * FAIL        specified data was in range, but doesn't exist
+ * PEND        operations was initiated but not completed
+ */
+#define        VM_PAGER_OK     0
+#define        VM_PAGER_BAD    1
+#define        VM_PAGER_FAIL   2
+#define        VM_PAGER_PEND   3
+
+#define        VM_PAGER_ALLOC(h, s, p)         (*(pg)->pg_ops->pgo_alloc)(h, s, p)
+#define        VM_PAGER_DEALLOC(pg)            (*(pg)->pg_ops->pgo_dealloc)(pg)
+#define        VM_PAGER_GET(pg, m, s)          (*(pg)->pg_ops->pgo_getpage)(pg, m, s)
+#define        VM_PAGER_PUT(pg, m, s)          (*(pg)->pg_ops->pgo_putpage)(pg, m, s)
+#define        VM_PAGER_HASPAGE(pg, o)         (*(pg)->pg_ops->pgo_haspage)(pg, o)
+
+#ifdef KERNEL
+vm_pager_t     vm_pager_allocate();
+void           vm_pager_deallocate();
+int            vm_pager_get();
+int            vm_pager_put();
+boolean_t      vm_pager_has_page();
+
+vm_offset_t    vm_pager_map_page();
+void           vm_pager_unmap_page();
+vm_pager_t     vm_pager_lookup();
+void           vm_pager_sync();
+
+extern struct pagerops *dfltpagerops;
+#endif
+
+#endif /* _VM_PAGER_ */
diff --git a/usr/src/sys.386bsd/vm/vm_param.h b/usr/src/sys.386bsd/vm/vm_param.h
new file mode 100644 (file)
index 0000000..8f530d0
--- /dev/null
@@ -0,0 +1,151 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_param.h  7.2 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Machine independent virtual memory parameters.
+ */
+
+#ifndef        _VM_PARAM_
+#define        _VM_PARAM_
+
+#ifdef KERNEL
+#include "machine/vmparam.h"
+#else
+#include <machine/vmparam.h>
+#endif
+
+/*
+ * This belongs in types.h, but breaks too many existing programs.
+ */
+typedef int    boolean_t;
+#define        TRUE    1
+#define        FALSE   0
+
+/*
+ *     The machine independent pages are refered to as PAGES.  A page
+ *     is some number of hardware pages, depending on the target machine.
+ */
+
+/*
+ *     All references to the size of a page should be done with PAGE_SIZE
+ *     or PAGE_SHIFT.  The fact they are variables is hidden here so that
+ *     we can easily make them constant if we so desire.
+ */
+
+#define        PAGE_SIZE       page_size       /* size of page in addressible units */
+#define PAGE_SHIFT     page_shift      /* number of bits to shift for pages */
+
+/* 
+ *     Return values from the VM routines.
+ */
+#define        KERN_SUCCESS            0
+#define        KERN_INVALID_ADDRESS    1
+#define        KERN_PROTECTION_FAILURE 2
+#define        KERN_NO_SPACE           3
+#define        KERN_INVALID_ARGUMENT   4
+#define        KERN_FAILURE            5
+#define        KERN_RESOURCE_SHORTAGE  6
+#define        KERN_NOT_RECEIVER       7
+#define        KERN_NO_ACCESS          8
+
+#ifdef ASSEMBLER
+#else  ASSEMBLER
+/*
+ *     Convert addresses to pages and vice versa.
+ *     No rounding is used.
+ */
+
+#ifdef KERNEL
+#define        atop(x)         (((unsigned)(x)) >> page_shift)
+#define        ptoa(x)         ((vm_offset_t)((x) << page_shift))
+#endif KERNEL
+
+/*
+ *     Round off or truncate to the nearest page.  These will work
+ *     for either addresses or counts.  (i.e. 1 byte rounds to 1 page
+ *     bytes.
+ */
+
+#ifdef KERNEL
+#define round_page(x)  ((vm_offset_t)((((vm_offset_t)(x)) + page_mask) & ~page_mask))
+#define trunc_page(x)  ((vm_offset_t)(((vm_offset_t)(x)) & ~page_mask))
+#else  KERNEL
+#define        round_page(x)   ((((vm_offset_t)(x) + (vm_page_size - 1)) / vm_page_size) * vm_page_size)
+#define        trunc_page(x)   ((((vm_offset_t)(x)) / vm_page_size) * vm_page_size)
+#endif KERNEL
+
+#ifdef KERNEL
+extern vm_size_t       page_size;      /* machine independent page size */
+extern vm_size_t       page_mask;      /* page_size - 1; mask for
+                                                  offset within page */
+extern int             page_shift;     /* shift to use for page size */
+
+extern vm_size_t       mem_size;       /* size of physical memory (bytes) */
+extern vm_offset_t     first_addr;     /* first physical page */
+extern vm_offset_t     last_addr;      /* last physical page */
+#endif KERNEL
+
+#endif ASSEMBLER
+
+#endif _VM_PARAM_
diff --git a/usr/src/sys.386bsd/vm/vm_prot.h b/usr/src/sys.386bsd/vm/vm_prot.h
new file mode 100644 (file)
index 0000000..dc01b13
--- /dev/null
@@ -0,0 +1,102 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_prot.h   7.2 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Virtual memory protection definitions.
+ */
+
+#ifndef        _VM_PROT_
+#define        _VM_PROT_
+
+/*
+ *     Types defined:
+ *
+ *     vm_prot_t               VM protection values.
+ */
+
+typedef int            vm_prot_t;
+
+/*
+ *     Protection values, defined as bits within the vm_prot_t type
+ */
+
+#define        VM_PROT_NONE    ((vm_prot_t) 0x00)
+
+#define VM_PROT_READ   ((vm_prot_t) 0x01)      /* read permission */
+#define VM_PROT_WRITE  ((vm_prot_t) 0x02)      /* write permission */
+#define VM_PROT_EXECUTE        ((vm_prot_t) 0x04)      /* execute permission */
+
+/*
+ *     The default protection for newly-created virtual memory
+ */
+
+#define VM_PROT_DEFAULT        (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)
+
+/*
+ *     The maximum privileges possible, for parameter checking.
+ */
+
+#define VM_PROT_ALL    (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)
+
+#endif _VM_PROT_
diff --git a/usr/src/sys.386bsd/vm/vm_statistics.h b/usr/src/sys.386bsd/vm/vm_statistics.h
new file mode 100644 (file)
index 0000000..82a85c7
--- /dev/null
@@ -0,0 +1,108 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_statistics.h     7.2 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young, David Golub
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Virtual memory statistics structure.
+ */
+
+#ifndef        _VM_STATISTICS_
+#define        _VM_STATISTICS_
+
+struct vm_statistics {
+       long    pagesize;               /* page size in bytes */
+       long    free_count;             /* # of pages free */
+       long    active_count;           /* # of pages active */
+       long    inactive_count;         /* # of pages inactive */
+       long    wire_count;             /* # of pages wired down */
+       long    zero_fill_count;        /* # of zero fill pages */
+       long    reactivations;          /* # of pages reactivated */
+       long    pageins;                /* # of pageins */
+       long    pageouts;               /* # of pageouts */
+       long    faults;                 /* # of faults */
+       long    cow_faults;             /* # of copy-on-writes */
+       long    lookups;                /* object cache lookups */
+       long    hits;                   /* object cache hits */
+};
+
+typedef struct vm_statistics   *vm_statistics_t;
+typedef struct vm_statistics   vm_statistics_data_t;
+
+#ifdef KERNEL
+vm_statistics_data_t   vm_stat;
+#endif KERNEL
+
+/*
+ *     Each machine dependent implementation is expected to
+ *     keep certain statistics.  They may do this anyway they
+ *     so choose, but are expected to return the statistics
+ *     in the following structure.
+ */
+
+struct pmap_statistics {
+       long            resident_count; /* # of pages mapped (total)*/
+       long            wired_count;    /* # of pages wired */
+};
+
+typedef struct pmap_statistics *pmap_statistics_t;
+#endif _VM_STATISTICS_
diff --git a/usr/src/sys.386bsd/vm/vm_user.c b/usr/src/sys.386bsd/vm/vm_user.c
new file mode 100644 (file)
index 0000000..0457a66
--- /dev/null
@@ -0,0 +1,246 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_user.c   7.3 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     User-exported virtual memory functions.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+
+#include "vm.h"
+#include "vm_page.h"
+
+simple_lock_data_t     vm_alloc_lock;  /* XXX */
+
+#ifdef MACHVMCOMPAT
+/*
+ * BSD style syscall interfaces to MACH calls
+ * All return MACH return values.
+ */
+/* ARGSUSED */
+svm_allocate(p, uap, retval)
+       struct proc *p;
+       struct args {
+               vm_map_t map;
+               vm_offset_t *addr;
+               vm_size_t size;
+               boolean_t anywhere;
+       } *uap;
+       int *retval;
+{
+       vm_offset_t addr;
+       int rv;
+
+       uap->map = p->p_map;            /* XXX */
+
+       if (copyin((caddr_t)uap->addr, (caddr_t)&addr, sizeof (addr)))
+               rv = KERN_INVALID_ARGUMENT;
+       else
+               rv = vm_allocate(uap->map, &addr, uap->size, uap->anywhere);
+       if (rv == KERN_SUCCESS) {
+               if (copyout((caddr_t)&addr, (caddr_t)uap->addr, sizeof(addr)))
+                       rv = KERN_INVALID_ARGUMENT;
+       }
+       return((int)rv);
+}
+
+/* ARGSUSED */
+svm_deallocate(p, uap, retval)
+       struct proc *p;
+       struct args {
+               vm_map_t map;
+               vm_offset_t addr;
+               vm_size_t size;
+       } *uap;
+       int *retval;
+{
+       int rv;
+
+       uap->map = p->p_map;            /* XXX */
+       rv = vm_deallocate(uap->map, uap->addr, uap->size);
+       return((int)rv);
+}
+
+/* ARGSUSED */
+svm_inherit(p, uap, retval)
+       struct proc *p;
+       struct args {
+               vm_map_t map;
+               vm_offset_t addr;
+               vm_size_t size;
+               vm_inherit_t inherit;
+       } *uap;
+       int *retval;
+{
+       int rv;
+
+       uap->map = p->p_map;            /* XXX */
+       rv = vm_inherit(uap->map, uap->addr, uap->size, uap->inherit);
+       return((int)rv);
+}
+
+/* ARGSUSED */
+svm_protect(p, uap, retval)
+       struct proc *p;
+       struct args {
+               vm_map_t map;
+               vm_offset_t addr;
+               vm_size_t size;
+               boolean_t setmax;
+               vm_prot_t prot;
+       } *uap;
+       int *retval;
+{
+       int rv;
+
+       uap->map = p->p_map;            /* XXX */
+       rv = vm_protect(uap->map, uap->addr, uap->size, uap->setmax, uap->prot);
+       return((int)rv);
+}
+#endif
+
+/*
+ *     vm_allocate allocates "zero fill" memory in the specfied
+ *     map.
+ */
+vm_allocate(map, addr, size, anywhere)
+       register vm_map_t       map;
+       register vm_offset_t    *addr;
+       register vm_size_t      size;
+       boolean_t               anywhere;
+{
+       int     result;
+
+       if (map == NULL)
+               return(KERN_INVALID_ARGUMENT);
+       if (size == 0) {
+               *addr = 0;
+               return(KERN_SUCCESS);
+       }
+
+       if (anywhere)
+               *addr = vm_map_min(map);
+       else
+               *addr = trunc_page(*addr);
+       size = round_page(size);
+
+       result = vm_map_find(map, NULL, (vm_offset_t) 0, addr,
+                       size, anywhere);
+
+       return(result);
+}
+
+/*
+ *     vm_deallocate deallocates the specified range of addresses in the
+ *     specified address map.
+ */
+vm_deallocate(map, start, size)
+       register vm_map_t       map;
+       vm_offset_t             start;
+       vm_size_t               size;
+{
+       if (map == NULL)
+               return(KERN_INVALID_ARGUMENT);
+
+       if (size == (vm_offset_t) 0)
+               return(KERN_SUCCESS);
+
+       return(vm_map_remove(map, trunc_page(start), round_page(start+size)));
+}
+
+/*
+ *     vm_inherit sets the inheritence of the specified range in the
+ *     specified map.
+ */
+vm_inherit(map, start, size, new_inheritance)
+       register vm_map_t       map;
+       vm_offset_t             start;
+       vm_size_t               size;
+       vm_inherit_t            new_inheritance;
+{
+       if (map == NULL)
+               return(KERN_INVALID_ARGUMENT);
+
+       return(vm_map_inherit(map, trunc_page(start), round_page(start+size), new_inheritance));
+}
+
+/*
+ *     vm_protect sets the protection of the specified range in the
+ *     specified map.
+ */
+
+vm_protect(map, start, size, set_maximum, new_protection)
+       register vm_map_t       map;
+       vm_offset_t             start;
+       vm_size_t               size;
+       boolean_t               set_maximum;
+       vm_prot_t               new_protection;
+{
+       if (map == NULL)
+               return(KERN_INVALID_ARGUMENT);
+
+       return(vm_map_protect(map, trunc_page(start), round_page(start+size), new_protection, set_maximum));
+}
diff --git a/usr/src/sys.386bsd/vm/vm_user.h b/usr/src/sys.386bsd/vm/vm_user.h
new file mode 100644 (file)
index 0000000..be75db3
--- /dev/null
@@ -0,0 +1,78 @@
+/* 
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vm_user.h   7.2 (Berkeley) 4/21/91
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Avadis Tevanian, Jr., Michael Wayne Young
+ * 
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *     Kernel memory management definitions.
+ */
+
+#ifndef        _VM_USER_
+#define        _VM_USER_
+
+int    vm_allocate();
+int    vm_deallocate();
+int    vm_inherit();
+int    vm_protect();
+int    vm_statistics();
+
+#endif _VM_USER_
diff --git a/usr/src/sys.386bsd/vm/vnode_pager.c b/usr/src/sys.386bsd/vm/vnode_pager.c
new file mode 100644 (file)
index 0000000..635c0fe
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 1990 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vnode_pager.c       7.5 (Berkeley) 4/20/91
+ */
+
+/*
+ * Page to/from files (vnodes).
+ *
+ * TODO:
+ *     pageouts
+ *     fix credential use (uses current process credentials now)
+ */
+#include "vnodepager.h"
+#if NVNODEPAGER > 0
+
+#include "param.h"
+#include "proc.h"
+#include "malloc.h"
+#include "vnode.h"
+#include "uio.h"
+#include "mount.h"
+
+#include "vm_param.h"
+#include "lock.h"
+#include "queue.h"
+#include "vm_prot.h"
+#include "vm_object.h"
+#include "vm_page.h"
+#include "vnode_pager.h"
+
+queue_head_t   vnode_pager_list;       /* list of managed vnodes */
+
+#ifdef DEBUG
+int    vpagerdebug = 0x00;
+#define        VDB_FOLLOW      0x01
+#define VDB_INIT       0x02
+#define VDB_IO         0x04
+#define VDB_FAIL       0x08
+#define VDB_ALLOC      0x10
+#define VDB_SIZE       0x20
+#endif
+
+void
+vnode_pager_init()
+{
+#ifdef DEBUG
+       if (vpagerdebug & VDB_FOLLOW)
+               printf("vnode_pager_init()\n");
+#endif
+       queue_init(&vnode_pager_list);
+}
+
+/*
+ * Allocate (or lookup) pager for a vnode.
+ * Handle is a vnode pointer.
+ */
+vm_pager_t
+vnode_pager_alloc(handle, size, prot)
+       caddr_t handle;
+       vm_size_t size;
+       vm_prot_t prot;
+{
+       register vm_pager_t pager;
+       register vn_pager_t vnp;
+       vm_object_t object;
+       struct vattr vattr;
+       struct vnode *vp;
+       struct proc *p = curproc;       /* XXX */
+
+#ifdef DEBUG
+       if (vpagerdebug & (VDB_FOLLOW|VDB_ALLOC))
+               printf("vnode_pager_alloc(%x, %x, %x)\n", handle, size, prot);
+#endif
+       /*
+        * Pageout to vnode, no can do yet.
+        */
+       if (handle == NULL)
+               return(NULL);
+
+       /*
+        * Vnodes keep a pointer to any associated pager so no need to
+        * lookup with vm_pager_lookup.
+        */
+       vp = (struct vnode *)handle;
+       pager = (vm_pager_t)vp->v_vmdata;
+       if (pager == NULL) {
+               /*
+                * Allocate pager structures
+                */
+               pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
+               if (pager == NULL)
+                       return(NULL);
+               vnp = (vn_pager_t)malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
+               if (vnp == NULL) {
+                       free((caddr_t)pager, M_VMPAGER);
+                       return(NULL);
+               }
+               /*
+                * And an object of the appropriate size
+                */
+               if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) {
+                       object = vm_object_allocate(round_page(vattr.va_size));
+                       vm_object_enter(object, pager);
+                       vm_object_setpager(object, pager, 0, TRUE);
+               } else {
+                       free((caddr_t)vnp, M_VMPGDATA);
+                       free((caddr_t)pager, M_VMPAGER);
+                       return(NULL);
+               }
+               /*
+                * Hold a reference to the vnode and initialize pager data.
+                */
+               VREF(vp);
+               vnp->vnp_flags = 0;
+               vnp->vnp_vp = vp;
+               vnp->vnp_size = vattr.va_size;
+               queue_enter(&vnode_pager_list, pager, vm_pager_t, pg_list);
+               pager->pg_handle = handle;
+               pager->pg_type = PG_VNODE;
+               pager->pg_ops = &vnodepagerops;
+               pager->pg_data = (caddr_t)vnp;
+               vp->v_vmdata = (caddr_t)pager;
+       } else {
+               /*
+                * vm_object_lookup() will remove the object from the
+                * cache if found and also gain a reference to the object.
+                */
+               object = vm_object_lookup(pager);
+#ifdef DEBUG
+               vnp = (vn_pager_t)pager->pg_data;
+#endif
+       }
+#ifdef DEBUG
+       if (vpagerdebug & VDB_ALLOC)
+               printf("vnode_pager_setup: vp %x sz %x pager %x object %x\n",
+                      vp, vnp->vnp_size, pager, object);
+#endif
+       return(pager);
+}
+
+void
+vnode_pager_dealloc(pager)
+       vm_pager_t pager;
+{
+       register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
+       register struct vnode *vp;
+       struct proc *p = curproc;               /* XXX */
+
+#ifdef DEBUG
+       if (vpagerdebug & VDB_FOLLOW)
+               printf("vnode_pager_dealloc(%x)\n", pager);
+#endif
+       if (vp = vnp->vnp_vp) {
+               vp->v_vmdata = NULL;
+               vp->v_flag &= ~VTEXT;
+#if 0
+               /* can hang if done at reboot on NFS FS */
+               (void) VOP_FSYNC(vp, p->p_ucred, p);
+#endif
+               vrele(vp);
+       }
+       queue_remove(&vnode_pager_list, pager, vm_pager_t, pg_list);
+       free((caddr_t)vnp, M_VMPGDATA);
+       free((caddr_t)pager, M_VMPAGER);
+}
+
+vnode_pager_getpage(pager, m, sync)
+       vm_pager_t pager;
+       vm_page_t m;
+       boolean_t sync;
+{
+
+#ifdef DEBUG
+       if (vpagerdebug & VDB_FOLLOW)
+               printf("vnode_pager_getpage(%x, %x)\n", pager, m);
+#endif
+       return(vnode_pager_io((vn_pager_t)pager->pg_data, m, UIO_READ));
+}
+
+boolean_t
+vnode_pager_putpage(pager, m, sync)
+       vm_pager_t pager;
+       vm_page_t m;
+       boolean_t sync;
+{
+       int err;
+
+#ifdef DEBUG
+       if (vpagerdebug & VDB_FOLLOW)
+               printf("vnode_pager_putpage(%x, %x)\n", pager, m);
+#endif
+       if (pager == NULL)
+               return;
+       err = vnode_pager_io((vn_pager_t)pager->pg_data, m, UIO_WRITE);
+       if (err == VM_PAGER_OK) {
+               m->clean = TRUE;                        /* XXX - wrong place */
+               pmap_clear_modify(VM_PAGE_TO_PHYS(m));  /* XXX - wrong place */
+       }
+       return(err);
+}
+
+boolean_t
+vnode_pager_haspage(pager, offset)
+       vm_pager_t pager;
+       vm_offset_t offset;
+{
+       register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
+       daddr_t bn;
+       int err;
+
+#ifdef DEBUG
+       if (vpagerdebug & VDB_FOLLOW)
+               printf("vnode_pager_haspage(%x, %x)\n", pager, offset);
+#endif
+
+       /*
+        * Offset beyond end of file, do not have the page
+        */
+       if (offset >= vnp->vnp_size) {
+#ifdef DEBUG
+               if (vpagerdebug & (VDB_FAIL|VDB_SIZE))
+                       printf("vnode_pager_haspage: pg %x, off %x, size %x\n",
+                              pager, offset, vnp->vnp_size);
+#endif
+               return(FALSE);
+       }
+
+       /*
+        * Read the index to find the disk block to read
+        * from.  If there is no block, report that we don't
+        * have this data.
+        *
+        * Assumes that the vnode has whole page or nothing.
+        */
+       err = VOP_BMAP(vnp->vnp_vp,
+                      offset / vnp->vnp_vp->v_mount->mnt_stat.f_bsize,
+                      (struct vnode **)0, &bn);
+       if (err) {
+#ifdef DEBUG
+               if (vpagerdebug & VDB_FAIL)
+                       printf("vnode_pager_haspage: BMAP err %d, pg %x, off %x\n",
+                              err, pager, offset);
+#endif
+               return(TRUE);
+       }
+       return((long)bn < 0 ? FALSE : TRUE);
+}
+
+/*
+ * (XXX)
+ * Lets the VM system know about a change in size for a file.
+ * If this vnode is mapped into some address space (i.e. we have a pager
+ * for it) we adjust our own internal size and flush any cached pages in
+ * the associated object that are affected by the size change.
+ *
+ * Note: this routine may be invoked as a result of a pager put
+ * operation (possibly at object termination time), so we must be careful.
+ */
+vnode_pager_setsize(vp, nsize)
+       struct vnode *vp;
+       u_long nsize;
+{
+       register vn_pager_t vnp;
+       register vm_object_t object;
+       vm_pager_t pager;
+
+       /*
+        * Not a mapped vnode
+        */
+       if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL)
+               return;
+       /*
+        * Hasn't changed size
+        */
+       pager = (vm_pager_t)vp->v_vmdata;
+       vnp = (vn_pager_t)pager->pg_data;
+       if (nsize == vnp->vnp_size)
+               return;
+       /*
+        * No object.
+        * This can happen during object termination since
+        * vm_object_page_clean is called after the object
+        * has been removed from the hash table, and clean
+        * may cause vnode write operations which can wind
+        * up back here.
+        */
+       object = vm_object_lookup(pager);
+       if (object == NULL)
+               return;
+
+#ifdef DEBUG
+       if (vpagerdebug & (VDB_FOLLOW|VDB_SIZE))
+               printf("vnode_pager_setsize: vp %x obj %x osz %d nsz %d\n",
+                      vp, object, vnp->vnp_size, nsize);
+#endif
+       /*
+        * File has shrunk.
+        * Toss any cached pages beyond the new EOF.
+        */
+       if (nsize < vnp->vnp_size) {
+               vm_object_lock(object);
+               vm_object_page_remove(object,
+                                     (vm_offset_t)nsize, vnp->vnp_size);
+               vm_object_unlock(object);
+       }
+       vnp->vnp_size = (vm_offset_t)nsize;
+       vm_object_deallocate(object);
+}
+
+vnode_pager_umount(mp)
+       register struct mount *mp;
+{
+       register vm_pager_t pager, npager;
+       struct vnode *vp;
+
+       pager = (vm_pager_t) queue_first(&vnode_pager_list);
+       while (!queue_end(&vnode_pager_list, (queue_entry_t)pager)) {
+               /*
+                * Save the next pointer now since uncaching may
+                * terminate the object and render pager invalid
+                */
+               vp = ((vn_pager_t)pager->pg_data)->vnp_vp;
+               npager = (vm_pager_t) queue_next(&pager->pg_list);
+               if (mp == (struct mount *)0 || vp->v_mount == mp)
+                       (void) vnode_pager_uncache(vp);
+               pager = npager;
+       }
+}
+
+/*
+ * Remove vnode associated object from the object cache.
+ *
+ * Note: this routine may be invoked as a result of a pager put
+ * operation (possibly at object termination time), so we must be careful.
+ */
+boolean_t
+vnode_pager_uncache(vp)
+       register struct vnode *vp;
+{
+       register vm_object_t object;
+       boolean_t uncached, locked;
+       vm_pager_t pager;
+
+       /*
+        * Not a mapped vnode
+        */
+       pager = (vm_pager_t)vp->v_vmdata;
+       if (pager == NULL)
+               return (TRUE);
+       /*
+        * Unlock the vnode if it is currently locked.
+        * We do this since uncaching the object may result
+        * in its destruction which may initiate paging
+        * activity which may necessitate locking the vnode.
+        */
+       locked = VOP_ISLOCKED(vp);
+       if (locked)
+               VOP_UNLOCK(vp);
+       /*
+        * Must use vm_object_lookup() as it actually removes
+        * the object from the cache list.
+        */
+       object = vm_object_lookup(pager);
+       if (object) {
+               uncached = (object->ref_count <= 1);
+               pager_cache(object, FALSE);
+       } else
+               uncached = TRUE;
+       if (locked)
+               VOP_LOCK(vp);
+       return(uncached);
+}
+
+vnode_pager_io(vnp, m, rw)
+       register vn_pager_t vnp;
+       vm_page_t m;
+       enum uio_rw rw;
+{
+       struct uio auio;
+       struct iovec aiov;
+       vm_offset_t kva, foff;
+       int error, size;
+       struct proc *p = curproc;               /* XXX */
+
+#ifdef DEBUG
+       if (vpagerdebug & VDB_FOLLOW)
+               printf("vnode_pager_io(%x, %x, %c): vnode %x\n",
+                      vnp, m, rw == UIO_READ ? 'R' : 'W', vnp->vnp_vp);
+#endif
+       foff = m->offset + m->object->paging_offset;
+       /*
+        * Return failure if beyond current EOF
+        */
+       if (foff >= vnp->vnp_size) {
+#ifdef DEBUG
+               if (vpagerdebug & VDB_SIZE)
+                       printf("vnode_pager_io: vp %x, off %d size %d\n",
+                              vnp->vnp_vp, foff, vnp->vnp_size);
+#endif
+               return(VM_PAGER_BAD);
+       }
+       if (foff + PAGE_SIZE > vnp->vnp_size)
+               size = vnp->vnp_size - foff;
+       else
+               size = PAGE_SIZE;
+       /*
+        * Allocate a kernel virtual address and initialize so that
+        * we can use VOP_READ/WRITE routines.
+        */
+       kva = vm_pager_map_page(m);
+       aiov.iov_base = (caddr_t)kva;
+       aiov.iov_len = size;
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       auio.uio_offset = foff;
+       auio.uio_segflg = UIO_SYSSPACE;
+       auio.uio_rw = rw;
+       auio.uio_resid = size;
+       auio.uio_procp = (struct proc *)0;
+#ifdef DEBUG
+       if (vpagerdebug & VDB_IO)
+               printf("vnode_pager_io: vp %x kva %x foff %x size %x",
+                      vnp->vnp_vp, kva, foff, size);
+#endif
+       if (rw == UIO_READ)
+               error = VOP_READ(vnp->vnp_vp, &auio, 0, p->p_ucred);
+       else
+               error = VOP_WRITE(vnp->vnp_vp, &auio, 0, p->p_ucred);
+#ifdef DEBUG
+       if (vpagerdebug & VDB_IO) {
+               if (error || auio.uio_resid)
+                       printf(" returns error %x, resid %x",
+                              error, auio.uio_resid);
+               printf("\n");
+       }
+#endif
+       if (!error) {
+               register int count = size - auio.uio_resid;
+
+               if (count == 0)
+                       error = EINVAL;
+               else if (count != PAGE_SIZE && rw == UIO_READ)
+                       bzero(kva + count, PAGE_SIZE - count);
+       }
+       vm_pager_unmap_page(kva);
+       return (error ? VM_PAGER_FAIL : VM_PAGER_OK);
+}
+#endif
diff --git a/usr/src/sys.386bsd/vm/vnode_pager.h b/usr/src/sys.386bsd/vm/vnode_pager.h
new file mode 100644 (file)
index 0000000..cf24d4b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1990 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vnode_pager.h       7.1 (Berkeley) 12/5/90
+ */
+
+#ifndef        _VNODE_PAGER_
+#define        _VNODE_PAGER_   1
+
+/*
+ * VNODE pager private data.
+ */
+struct vnpager {
+       int             vnp_flags;      /* flags */
+       struct vnode    *vnp_vp;        /* vnode */
+       vm_size_t       vnp_size;       /* vnode current size */
+};
+typedef struct vnpager *vn_pager_t;
+
+#define VN_PAGER_NULL  ((vn_pager_t)0)
+
+#define        VNP_PAGING      0x01            /* vnode used for pageout */
+#define VNP_CACHED     0x02            /* vnode is cached */
+
+#ifdef KERNEL
+
+void           vnode_pager_init();
+vm_pager_t     vnode_pager_alloc();
+void           vnode_pager_dealloc();
+int            vnode_pager_getpage(), vnode_pager_putpage();
+boolean_t      vnode_pager_haspage();
+
+struct pagerops vnodepagerops = {
+       vnode_pager_init,
+       vnode_pager_alloc,
+       vnode_pager_dealloc,
+       vnode_pager_getpage,
+       vnode_pager_putpage,
+       vnode_pager_haspage
+};
+
+#endif
+
+#endif /* _VNODE_PAGER_ */