From b688fc87180e0c3ea6fb4bcdfef4934e73602ef0 Mon Sep 17 00:00:00 2001 From: "William F. Jolitz" Date: Tue, 24 Dec 1991 14:24:24 -0800 Subject: [PATCH] 386BSD 0.1 development 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 Synthesized-from: 386BSD-0.1 --- usr/src/sys.386bsd/conf/defines | 15 + usr/src/sys.386bsd/conf/nfsswapvmunix.c | 151 ++ usr/src/sys.386bsd/conf/param.c | 138 ++ usr/src/sys.386bsd/i386/Makefile | 24 + usr/src/sys.386bsd/kern/dead_vnops.c | 417 +++++ usr/src/sys.386bsd/kern/fifo_vnops.c | 420 +++++ usr/src/sys.386bsd/kern/init_sysent.c | 438 ++++++ usr/src/sys.386bsd/kern/kern_acct.c | 127 ++ usr/src/sys.386bsd/kern/kern_kinfo.c | 300 ++++ usr/src/sys.386bsd/kern/kern_ktrace.c | 414 +++++ usr/src/sys.386bsd/kern/kern_time.c | 377 +++++ usr/src/sys.386bsd/kern/kern_xxx.c | 127 ++ usr/src/sys.386bsd/kern/subr_xxx.c | 209 +++ usr/src/sys.386bsd/kern/sys_generic.c | 648 ++++++++ usr/src/sys.386bsd/kern/sys_socket.c | 193 +++ usr/src/sys.386bsd/kern/syscalls.c | 229 +++ usr/src/sys.386bsd/kern/sysv_shm.c | 519 +++++++ usr/src/sys.386bsd/kern/tty_compat.c | 398 +++++ usr/src/sys.386bsd/kern/tty_conf.c | 103 ++ usr/src/sys.386bsd/kern/tty_tb.c | 366 +++++ usr/src/sys.386bsd/kern/tty_tty.c | 135 ++ usr/src/sys.386bsd/kern/uipc_domain.c | 176 +++ usr/src/sys.386bsd/kern/uipc_proto.c | 72 + usr/src/sys.386bsd/kern/uipc_socket.c | 991 ++++++++++++ usr/src/sys.386bsd/kern/uipc_socket2.c | 779 ++++++++++ usr/src/sys.386bsd/kern/vfs_cache.c | 322 ++++ usr/src/sys.386bsd/kern/vfs_lookup.c | 456 ++++++ usr/src/sys.386bsd/kern/vfs_subr.c | 1185 ++++++++++++++ usr/src/sys.386bsd/net/af.c | 46 + usr/src/sys.386bsd/net/af.h | 64 + usr/src/sys.386bsd/net/bpf.h | 219 +++ usr/src/sys.386bsd/net/bpf_filter.c | 549 +++++++ usr/src/sys.386bsd/net/bpfdesc.h | 87 ++ usr/src/sys.386bsd/net/if.c | 634 ++++++++ usr/src/sys.386bsd/net/if_arp.h | 78 + usr/src/sys.386bsd/net/if_dl.h | 80 + usr/src/sys.386bsd/net/if_ethersubr.c | 417 +++++ usr/src/sys.386bsd/net/if_llc.h | 82 + usr/src/sys.386bsd/net/if_loop.c | 188 +++ usr/src/sys.386bsd/net/if_slvar.h | 73 + usr/src/sys.386bsd/net/if_types.h | 64 + usr/src/sys.386bsd/net/netisr.h | 86 ++ usr/src/sys.386bsd/net/radix.c | 639 ++++++++ usr/src/sys.386bsd/net/radix.h | 118 ++ usr/src/sys.386bsd/net/raw_cb.c | 142 ++ usr/src/sys.386bsd/net/raw_cb.h | 59 + usr/src/sys.386bsd/net/raw_usrreq.c | 308 ++++ usr/src/sys.386bsd/net/route.c | 507 ++++++ usr/src/sys.386bsd/net/route.h | 223 +++ usr/src/sys.386bsd/net/rtsock.c | 658 ++++++++ usr/src/sys.386bsd/net/slcompress.c | 535 +++++++ usr/src/sys.386bsd/net/slcompress.h | 157 ++ usr/src/sys.386bsd/netinet/icmp_var.h | 57 + usr/src/sys.386bsd/netinet/if_ether.c | 607 ++++++++ usr/src/sys.386bsd/netinet/if_ether.h | 108 ++ usr/src/sys.386bsd/netinet/in.c | 597 ++++++++ usr/src/sys.386bsd/netinet/in.h | 151 ++ usr/src/sys.386bsd/netinet/in_cksum.c | 148 ++ usr/src/sys.386bsd/netinet/in_pcb.c | 441 ++++++ usr/src/sys.386bsd/netinet/in_pcb.h | 91 ++ usr/src/sys.386bsd/netinet/in_systm.h | 56 + usr/src/sys.386bsd/netinet/in_var.h | 76 + usr/src/sys.386bsd/netinet/ip.h | 166 ++ usr/src/sys.386bsd/netinet/ip_icmp.c | 519 +++++++ usr/src/sys.386bsd/netinet/ip_icmp.h | 133 ++ usr/src/sys.386bsd/netinet/ip_input.c | 1068 +++++++++++++ usr/src/sys.386bsd/netinet/ip_output.c | 602 ++++++++ usr/src/sys.386bsd/netinet/ip_var.h | 136 ++ usr/src/sys.386bsd/netinet/tcp.h | 84 + usr/src/sys.386bsd/netinet/tcp_debug.c | 158 ++ usr/src/sys.386bsd/netinet/tcp_debug.h | 59 + usr/src/sys.386bsd/netinet/tcp_fsm.h | 85 ++ usr/src/sys.386bsd/netinet/tcp_input.c | 1493 ++++++++++++++++++ usr/src/sys.386bsd/netinet/tcp_output.c | 503 ++++++ usr/src/sys.386bsd/netinet/tcp_seq.h | 62 + usr/src/sys.386bsd/netinet/tcp_subr.c | 415 +++++ usr/src/sys.386bsd/netinet/tcp_timer.c | 304 ++++ usr/src/sys.386bsd/netinet/tcp_timer.h | 129 ++ usr/src/sys.386bsd/netinet/tcp_usrreq.c | 498 ++++++ usr/src/sys.386bsd/netinet/tcp_var.h | 218 +++ usr/src/sys.386bsd/netinet/tcpip.h | 59 + usr/src/sys.386bsd/netinet/udp.h | 45 + usr/src/sys.386bsd/netinet/udp_usrreq.c | 514 +++++++ usr/src/sys.386bsd/netinet/udp_var.h | 74 + usr/src/sys.386bsd/nfs/nfs.h | 164 ++ usr/src/sys.386bsd/nfs/nfs_bio.c | 305 ++++ usr/src/sys.386bsd/nfs/nfs_node.c | 325 ++++ usr/src/sys.386bsd/nfs/nfs_serv.c | 1495 ++++++++++++++++++ usr/src/sys.386bsd/nfs/nfs_socket.c | 1413 +++++++++++++++++ usr/src/sys.386bsd/nfs/nfs_srvcache.c | 300 ++++ usr/src/sys.386bsd/nfs/nfs_syscalls.c | 368 +++++ usr/src/sys.386bsd/nfs/nfs_vfsops.c | 599 ++++++++ usr/src/sys.386bsd/nfs/nfscompress.h | 78 + usr/src/sys.386bsd/nfs/nfsdiskless.h | 58 + usr/src/sys.386bsd/nfs/nfsiom.h | 45 + usr/src/sys.386bsd/nfs/nfsm_subs.h | 301 ++++ usr/src/sys.386bsd/nfs/nfsmount.h | 117 ++ usr/src/sys.386bsd/nfs/nfsnode.h | 221 +++ usr/src/sys.386bsd/nfs/nfsrvcache.h | 93 ++ usr/src/sys.386bsd/nfs/nfsv2.h | 159 ++ usr/src/sys.386bsd/nfs/rpcv2.h | 87 ++ usr/src/sys.386bsd/nfs/xdr_subs.h | 57 + usr/src/sys.386bsd/stand/cat.c | 44 + usr/src/sys.386bsd/stand/copy.c | 83 + usr/src/sys.386bsd/stand/dev.c | 158 ++ usr/src/sys.386bsd/stand/ls.c | 103 ++ usr/src/sys.386bsd/stand/saerrno.h | 54 + usr/src/sys.386bsd/stand/saioctl.h | 50 + usr/src/sys.386bsd/stand/stat.c | 74 + usr/src/sys.386bsd/sys/acct.h | 70 + usr/src/sys.386bsd/sys/callout.h | 46 + usr/src/sys.386bsd/sys/cdefs.h | 78 + usr/src/sys.386bsd/sys/clist.h | 45 + usr/src/sys.386bsd/sys/conf.h | 112 ++ usr/src/sys.386bsd/sys/dir.h | 61 + usr/src/sys.386bsd/sys/dkbad.h | 68 + usr/src/sys.386bsd/sys/dkstat.h | 58 + usr/src/sys.386bsd/sys/dmap.h | 60 + usr/src/sys.386bsd/sys/domain.h | 51 + usr/src/sys.386bsd/sys/errno.h | 153 ++ usr/src/sys.386bsd/sys/exec.h | 71 + usr/src/sys.386bsd/sys/fcntl.h | 181 +++ usr/src/sys.386bsd/sys/fifo.h | 180 +++ usr/src/sys.386bsd/sys/file.h | 73 + usr/src/sys.386bsd/sys/filedesc.h | 99 ++ usr/src/sys.386bsd/sys/gprof.h | 114 ++ usr/src/sys.386bsd/sys/ioctl.h | 224 +++ usr/src/sys.386bsd/sys/ioctl_compat.h | 167 ++ usr/src/sys.386bsd/sys/ipc.h | 74 + usr/src/sys.386bsd/sys/kernel.h | 65 + usr/src/sys.386bsd/sys/kinfo.h | 91 ++ usr/src/sys.386bsd/sys/kinfo_proc.h | 81 + usr/src/sys.386bsd/sys/ktrace.h | 144 ++ usr/src/sys.386bsd/sys/malloc.h | 265 ++++ usr/src/sys.386bsd/sys/mapmem.h | 112 ++ usr/src/sys.386bsd/sys/mbuf.h | 382 +++++ usr/src/sys.386bsd/sys/mman.h | 87 ++ usr/src/sys.386bsd/sys/msgbuf.h | 46 + usr/src/sys.386bsd/sys/mtio.h | 117 ++ usr/src/sys.386bsd/sys/namei.h | 167 ++ usr/src/sys.386bsd/sys/proc.h | 248 +++ usr/src/sys.386bsd/sys/protosw.h | 209 +++ usr/src/sys.386bsd/sys/ptrace.h | 60 + usr/src/sys.386bsd/sys/reboot.h | 87 ++ usr/src/sys.386bsd/sys/resource.h | 111 ++ usr/src/sys.386bsd/sys/shm.h | 94 ++ usr/src/sys.386bsd/sys/signalvar.h | 166 ++ usr/src/sys.386bsd/sys/socket.h | 260 ++++ usr/src/sys.386bsd/sys/socketvar.h | 199 +++ usr/src/sys.386bsd/sys/specdev.h | 220 +++ usr/src/sys.386bsd/sys/stat.h | 128 ++ usr/src/sys.386bsd/sys/syscall.h | 166 ++ usr/src/sys.386bsd/sys/syslimits.h | 54 + usr/src/sys.386bsd/sys/syslog.h | 178 +++ usr/src/sys.386bsd/sys/systm.h | 119 ++ usr/src/sys.386bsd/sys/tablet.h | 99 ++ usr/src/sys.386bsd/sys/termios.h | 268 ++++ usr/src/sys.386bsd/sys/time.h | 102 ++ usr/src/sys.386bsd/sys/timeb.h | 42 + usr/src/sys.386bsd/sys/times.h | 56 + usr/src/sys.386bsd/sys/tprintf.h | 41 + usr/src/sys.386bsd/sys/trace.h | 114 ++ usr/src/sys.386bsd/sys/ttychars.h | 63 + usr/src/sys.386bsd/sys/ttydefaults.h | 91 ++ usr/src/sys.386bsd/sys/ttydev.h | 60 + usr/src/sys.386bsd/sys/types.h | 135 ++ usr/src/sys.386bsd/sys/ucred.h | 58 + usr/src/sys.386bsd/sys/uio.h | 82 + usr/src/sys.386bsd/sys/un.h | 52 + usr/src/sys.386bsd/sys/unistd.h | 91 ++ usr/src/sys.386bsd/sys/unpcb.h | 73 + usr/src/sys.386bsd/sys/user.h | 90 ++ usr/src/sys.386bsd/sys/vadvise.h | 49 + usr/src/sys.386bsd/sys/vcmd.h | 43 + usr/src/sys.386bsd/sys/vlimit.h | 49 + usr/src/sys.386bsd/sys/vmmeter.h | 141 ++ usr/src/sys.386bsd/sys/vnode.h | 333 ++++ usr/src/sys.386bsd/sys/vsio.h | 153 ++ usr/src/sys.386bsd/sys/vtimes.h | 54 + usr/src/sys.386bsd/sys/wait.h | 158 ++ usr/src/sys.386bsd/ufs/dinode.h | 86 ++ usr/src/sys.386bsd/ufs/dir.h | 98 ++ usr/src/sys.386bsd/ufs/fs.h | 440 ++++++ usr/src/sys.386bsd/ufs/inode.h | 230 +++ usr/src/sys.386bsd/ufs/lockf.h | 71 + usr/src/sys.386bsd/ufs/mfs_vfsops.c | 196 +++ usr/src/sys.386bsd/ufs/mfsiom.h | 37 + usr/src/sys.386bsd/ufs/mfsnode.h | 196 +++ usr/src/sys.386bsd/ufs/quota.h | 182 +++ usr/src/sys.386bsd/ufs/ufs_alloc.c | 1101 ++++++++++++++ usr/src/sys.386bsd/ufs/ufs_bmap.c | 360 +++++ usr/src/sys.386bsd/ufs/ufs_inode.c | 697 +++++++++ usr/src/sys.386bsd/ufs/ufs_quota.c | 934 ++++++++++++ usr/src/sys.386bsd/ufs/ufs_subr.c | 210 +++ usr/src/sys.386bsd/ufs/ufs_tables.c | 140 ++ usr/src/sys.386bsd/ufs/ufs_vnops.c | 1863 +++++++++++++++++++++++ usr/src/sys.386bsd/ufs/ufsmount.h | 77 + usr/src/sys.386bsd/vm/device_pager.h | 78 + usr/src/sys.386bsd/vm/kern_lock.c | 533 +++++++ usr/src/sys.386bsd/vm/lock.h | 175 +++ usr/src/sys.386bsd/vm/pmap.h | 107 ++ usr/src/sys.386bsd/vm/queue.h | 133 ++ usr/src/sys.386bsd/vm/swap_pager.h | 112 ++ usr/src/sys.386bsd/vm/vm.h | 74 + usr/src/sys.386bsd/vm/vm_inherit.h | 91 ++ usr/src/sys.386bsd/vm/vm_init.c | 102 ++ usr/src/sys.386bsd/vm/vm_map.h | 204 +++ usr/src/sys.386bsd/vm/vm_meter.c | 143 ++ usr/src/sys.386bsd/vm/vm_object.c | 1449 ++++++++++++++++++ usr/src/sys.386bsd/vm/vm_object.h | 171 +++ usr/src/sys.386bsd/vm/vm_page.h | 261 ++++ usr/src/sys.386bsd/vm/vm_pageout.c | 387 +++++ usr/src/sys.386bsd/vm/vm_pageout.h | 90 ++ usr/src/sys.386bsd/vm/vm_pager.c | 282 ++++ usr/src/sys.386bsd/vm/vm_pager.h | 106 ++ usr/src/sys.386bsd/vm/vm_param.h | 151 ++ usr/src/sys.386bsd/vm/vm_prot.h | 102 ++ usr/src/sys.386bsd/vm/vm_statistics.h | 108 ++ usr/src/sys.386bsd/vm/vm_user.c | 246 +++ usr/src/sys.386bsd/vm/vm_user.h | 78 + usr/src/sys.386bsd/vm/vnode_pager.c | 483 ++++++ usr/src/sys.386bsd/vm/vnode_pager.h | 78 + 222 files changed, 53149 insertions(+) create mode 100644 usr/src/sys.386bsd/conf/defines create mode 100644 usr/src/sys.386bsd/conf/nfsswapvmunix.c create mode 100644 usr/src/sys.386bsd/conf/param.c create mode 100644 usr/src/sys.386bsd/i386/Makefile create mode 100644 usr/src/sys.386bsd/kern/dead_vnops.c create mode 100644 usr/src/sys.386bsd/kern/fifo_vnops.c create mode 100644 usr/src/sys.386bsd/kern/init_sysent.c create mode 100644 usr/src/sys.386bsd/kern/kern_acct.c create mode 100644 usr/src/sys.386bsd/kern/kern_kinfo.c create mode 100644 usr/src/sys.386bsd/kern/kern_ktrace.c create mode 100644 usr/src/sys.386bsd/kern/kern_time.c create mode 100644 usr/src/sys.386bsd/kern/kern_xxx.c create mode 100644 usr/src/sys.386bsd/kern/subr_xxx.c create mode 100644 usr/src/sys.386bsd/kern/sys_generic.c create mode 100644 usr/src/sys.386bsd/kern/sys_socket.c create mode 100644 usr/src/sys.386bsd/kern/syscalls.c create mode 100644 usr/src/sys.386bsd/kern/sysv_shm.c create mode 100644 usr/src/sys.386bsd/kern/tty_compat.c create mode 100644 usr/src/sys.386bsd/kern/tty_conf.c create mode 100644 usr/src/sys.386bsd/kern/tty_tb.c create mode 100644 usr/src/sys.386bsd/kern/tty_tty.c create mode 100644 usr/src/sys.386bsd/kern/uipc_domain.c create mode 100644 usr/src/sys.386bsd/kern/uipc_proto.c create mode 100644 usr/src/sys.386bsd/kern/uipc_socket.c create mode 100644 usr/src/sys.386bsd/kern/uipc_socket2.c create mode 100644 usr/src/sys.386bsd/kern/vfs_cache.c create mode 100644 usr/src/sys.386bsd/kern/vfs_lookup.c create mode 100644 usr/src/sys.386bsd/kern/vfs_subr.c create mode 100644 usr/src/sys.386bsd/net/af.c create mode 100644 usr/src/sys.386bsd/net/af.h create mode 100644 usr/src/sys.386bsd/net/bpf.h create mode 100644 usr/src/sys.386bsd/net/bpf_filter.c create mode 100644 usr/src/sys.386bsd/net/bpfdesc.h create mode 100644 usr/src/sys.386bsd/net/if.c create mode 100644 usr/src/sys.386bsd/net/if_arp.h create mode 100644 usr/src/sys.386bsd/net/if_dl.h create mode 100644 usr/src/sys.386bsd/net/if_ethersubr.c create mode 100644 usr/src/sys.386bsd/net/if_llc.h create mode 100644 usr/src/sys.386bsd/net/if_loop.c create mode 100644 usr/src/sys.386bsd/net/if_slvar.h create mode 100644 usr/src/sys.386bsd/net/if_types.h create mode 100644 usr/src/sys.386bsd/net/netisr.h create mode 100644 usr/src/sys.386bsd/net/radix.c create mode 100644 usr/src/sys.386bsd/net/radix.h create mode 100644 usr/src/sys.386bsd/net/raw_cb.c create mode 100644 usr/src/sys.386bsd/net/raw_cb.h create mode 100644 usr/src/sys.386bsd/net/raw_usrreq.c create mode 100644 usr/src/sys.386bsd/net/route.c create mode 100644 usr/src/sys.386bsd/net/route.h create mode 100644 usr/src/sys.386bsd/net/rtsock.c create mode 100644 usr/src/sys.386bsd/net/slcompress.c create mode 100644 usr/src/sys.386bsd/net/slcompress.h create mode 100644 usr/src/sys.386bsd/netinet/icmp_var.h create mode 100644 usr/src/sys.386bsd/netinet/if_ether.c create mode 100644 usr/src/sys.386bsd/netinet/if_ether.h create mode 100644 usr/src/sys.386bsd/netinet/in.c create mode 100644 usr/src/sys.386bsd/netinet/in.h create mode 100644 usr/src/sys.386bsd/netinet/in_cksum.c create mode 100644 usr/src/sys.386bsd/netinet/in_pcb.c create mode 100644 usr/src/sys.386bsd/netinet/in_pcb.h create mode 100644 usr/src/sys.386bsd/netinet/in_systm.h create mode 100644 usr/src/sys.386bsd/netinet/in_var.h create mode 100644 usr/src/sys.386bsd/netinet/ip.h create mode 100644 usr/src/sys.386bsd/netinet/ip_icmp.c create mode 100644 usr/src/sys.386bsd/netinet/ip_icmp.h create mode 100644 usr/src/sys.386bsd/netinet/ip_input.c create mode 100644 usr/src/sys.386bsd/netinet/ip_output.c create mode 100644 usr/src/sys.386bsd/netinet/ip_var.h create mode 100644 usr/src/sys.386bsd/netinet/tcp.h create mode 100644 usr/src/sys.386bsd/netinet/tcp_debug.c create mode 100644 usr/src/sys.386bsd/netinet/tcp_debug.h create mode 100644 usr/src/sys.386bsd/netinet/tcp_fsm.h create mode 100644 usr/src/sys.386bsd/netinet/tcp_input.c create mode 100644 usr/src/sys.386bsd/netinet/tcp_output.c create mode 100644 usr/src/sys.386bsd/netinet/tcp_seq.h create mode 100644 usr/src/sys.386bsd/netinet/tcp_subr.c create mode 100644 usr/src/sys.386bsd/netinet/tcp_timer.c create mode 100644 usr/src/sys.386bsd/netinet/tcp_timer.h create mode 100644 usr/src/sys.386bsd/netinet/tcp_usrreq.c create mode 100644 usr/src/sys.386bsd/netinet/tcp_var.h create mode 100644 usr/src/sys.386bsd/netinet/tcpip.h create mode 100644 usr/src/sys.386bsd/netinet/udp.h create mode 100644 usr/src/sys.386bsd/netinet/udp_usrreq.c create mode 100644 usr/src/sys.386bsd/netinet/udp_var.h create mode 100644 usr/src/sys.386bsd/nfs/nfs.h create mode 100644 usr/src/sys.386bsd/nfs/nfs_bio.c create mode 100644 usr/src/sys.386bsd/nfs/nfs_node.c create mode 100644 usr/src/sys.386bsd/nfs/nfs_serv.c create mode 100644 usr/src/sys.386bsd/nfs/nfs_socket.c create mode 100644 usr/src/sys.386bsd/nfs/nfs_srvcache.c create mode 100644 usr/src/sys.386bsd/nfs/nfs_syscalls.c create mode 100644 usr/src/sys.386bsd/nfs/nfs_vfsops.c create mode 100644 usr/src/sys.386bsd/nfs/nfscompress.h create mode 100644 usr/src/sys.386bsd/nfs/nfsdiskless.h create mode 100644 usr/src/sys.386bsd/nfs/nfsiom.h create mode 100644 usr/src/sys.386bsd/nfs/nfsm_subs.h create mode 100644 usr/src/sys.386bsd/nfs/nfsmount.h create mode 100644 usr/src/sys.386bsd/nfs/nfsnode.h create mode 100644 usr/src/sys.386bsd/nfs/nfsrvcache.h create mode 100644 usr/src/sys.386bsd/nfs/nfsv2.h create mode 100644 usr/src/sys.386bsd/nfs/rpcv2.h create mode 100644 usr/src/sys.386bsd/nfs/xdr_subs.h create mode 100644 usr/src/sys.386bsd/stand/cat.c create mode 100644 usr/src/sys.386bsd/stand/copy.c create mode 100644 usr/src/sys.386bsd/stand/dev.c create mode 100644 usr/src/sys.386bsd/stand/ls.c create mode 100644 usr/src/sys.386bsd/stand/saerrno.h create mode 100644 usr/src/sys.386bsd/stand/saioctl.h create mode 100644 usr/src/sys.386bsd/stand/stat.c create mode 100644 usr/src/sys.386bsd/sys/acct.h create mode 100644 usr/src/sys.386bsd/sys/callout.h create mode 100644 usr/src/sys.386bsd/sys/cdefs.h create mode 100644 usr/src/sys.386bsd/sys/clist.h create mode 100644 usr/src/sys.386bsd/sys/conf.h create mode 100644 usr/src/sys.386bsd/sys/dir.h create mode 100644 usr/src/sys.386bsd/sys/dkbad.h create mode 100644 usr/src/sys.386bsd/sys/dkstat.h create mode 100644 usr/src/sys.386bsd/sys/dmap.h create mode 100644 usr/src/sys.386bsd/sys/domain.h create mode 100644 usr/src/sys.386bsd/sys/errno.h create mode 100644 usr/src/sys.386bsd/sys/exec.h create mode 100644 usr/src/sys.386bsd/sys/fcntl.h create mode 100644 usr/src/sys.386bsd/sys/fifo.h create mode 100644 usr/src/sys.386bsd/sys/file.h create mode 100644 usr/src/sys.386bsd/sys/filedesc.h create mode 100644 usr/src/sys.386bsd/sys/gprof.h create mode 100644 usr/src/sys.386bsd/sys/ioctl.h create mode 100644 usr/src/sys.386bsd/sys/ioctl_compat.h create mode 100644 usr/src/sys.386bsd/sys/ipc.h create mode 100644 usr/src/sys.386bsd/sys/kernel.h create mode 100644 usr/src/sys.386bsd/sys/kinfo.h create mode 100644 usr/src/sys.386bsd/sys/kinfo_proc.h create mode 100644 usr/src/sys.386bsd/sys/ktrace.h create mode 100644 usr/src/sys.386bsd/sys/malloc.h create mode 100644 usr/src/sys.386bsd/sys/mapmem.h create mode 100644 usr/src/sys.386bsd/sys/mbuf.h create mode 100644 usr/src/sys.386bsd/sys/mman.h create mode 100644 usr/src/sys.386bsd/sys/msgbuf.h create mode 100644 usr/src/sys.386bsd/sys/mtio.h create mode 100644 usr/src/sys.386bsd/sys/namei.h create mode 100644 usr/src/sys.386bsd/sys/proc.h create mode 100644 usr/src/sys.386bsd/sys/protosw.h create mode 100644 usr/src/sys.386bsd/sys/ptrace.h create mode 100644 usr/src/sys.386bsd/sys/reboot.h create mode 100644 usr/src/sys.386bsd/sys/resource.h create mode 100644 usr/src/sys.386bsd/sys/shm.h create mode 100644 usr/src/sys.386bsd/sys/signalvar.h create mode 100644 usr/src/sys.386bsd/sys/socket.h create mode 100644 usr/src/sys.386bsd/sys/socketvar.h create mode 100644 usr/src/sys.386bsd/sys/specdev.h create mode 100644 usr/src/sys.386bsd/sys/stat.h create mode 100644 usr/src/sys.386bsd/sys/syscall.h create mode 100644 usr/src/sys.386bsd/sys/syslimits.h create mode 100644 usr/src/sys.386bsd/sys/syslog.h create mode 100644 usr/src/sys.386bsd/sys/systm.h create mode 100644 usr/src/sys.386bsd/sys/tablet.h create mode 100644 usr/src/sys.386bsd/sys/termios.h create mode 100644 usr/src/sys.386bsd/sys/time.h create mode 100644 usr/src/sys.386bsd/sys/timeb.h create mode 100644 usr/src/sys.386bsd/sys/times.h create mode 100644 usr/src/sys.386bsd/sys/tprintf.h create mode 100644 usr/src/sys.386bsd/sys/trace.h create mode 100644 usr/src/sys.386bsd/sys/ttychars.h create mode 100644 usr/src/sys.386bsd/sys/ttydefaults.h create mode 100644 usr/src/sys.386bsd/sys/ttydev.h create mode 100644 usr/src/sys.386bsd/sys/types.h create mode 100644 usr/src/sys.386bsd/sys/ucred.h create mode 100644 usr/src/sys.386bsd/sys/uio.h create mode 100644 usr/src/sys.386bsd/sys/un.h create mode 100644 usr/src/sys.386bsd/sys/unistd.h create mode 100644 usr/src/sys.386bsd/sys/unpcb.h create mode 100644 usr/src/sys.386bsd/sys/user.h create mode 100644 usr/src/sys.386bsd/sys/vadvise.h create mode 100644 usr/src/sys.386bsd/sys/vcmd.h create mode 100644 usr/src/sys.386bsd/sys/vlimit.h create mode 100644 usr/src/sys.386bsd/sys/vmmeter.h create mode 100644 usr/src/sys.386bsd/sys/vnode.h create mode 100644 usr/src/sys.386bsd/sys/vsio.h create mode 100644 usr/src/sys.386bsd/sys/vtimes.h create mode 100644 usr/src/sys.386bsd/sys/wait.h create mode 100644 usr/src/sys.386bsd/ufs/dinode.h create mode 100644 usr/src/sys.386bsd/ufs/dir.h create mode 100644 usr/src/sys.386bsd/ufs/fs.h create mode 100644 usr/src/sys.386bsd/ufs/inode.h create mode 100644 usr/src/sys.386bsd/ufs/lockf.h create mode 100644 usr/src/sys.386bsd/ufs/mfs_vfsops.c create mode 100644 usr/src/sys.386bsd/ufs/mfsiom.h create mode 100644 usr/src/sys.386bsd/ufs/mfsnode.h create mode 100644 usr/src/sys.386bsd/ufs/quota.h create mode 100644 usr/src/sys.386bsd/ufs/ufs_alloc.c create mode 100644 usr/src/sys.386bsd/ufs/ufs_bmap.c create mode 100644 usr/src/sys.386bsd/ufs/ufs_inode.c create mode 100644 usr/src/sys.386bsd/ufs/ufs_quota.c create mode 100644 usr/src/sys.386bsd/ufs/ufs_subr.c create mode 100644 usr/src/sys.386bsd/ufs/ufs_tables.c create mode 100644 usr/src/sys.386bsd/ufs/ufs_vnops.c create mode 100644 usr/src/sys.386bsd/ufs/ufsmount.h create mode 100644 usr/src/sys.386bsd/vm/device_pager.h create mode 100644 usr/src/sys.386bsd/vm/kern_lock.c create mode 100644 usr/src/sys.386bsd/vm/lock.h create mode 100644 usr/src/sys.386bsd/vm/pmap.h create mode 100644 usr/src/sys.386bsd/vm/queue.h create mode 100644 usr/src/sys.386bsd/vm/swap_pager.h create mode 100644 usr/src/sys.386bsd/vm/vm.h create mode 100644 usr/src/sys.386bsd/vm/vm_inherit.h create mode 100644 usr/src/sys.386bsd/vm/vm_init.c create mode 100644 usr/src/sys.386bsd/vm/vm_map.h create mode 100644 usr/src/sys.386bsd/vm/vm_meter.c create mode 100644 usr/src/sys.386bsd/vm/vm_object.c create mode 100644 usr/src/sys.386bsd/vm/vm_object.h create mode 100644 usr/src/sys.386bsd/vm/vm_page.h create mode 100644 usr/src/sys.386bsd/vm/vm_pageout.c create mode 100644 usr/src/sys.386bsd/vm/vm_pageout.h create mode 100644 usr/src/sys.386bsd/vm/vm_pager.c create mode 100644 usr/src/sys.386bsd/vm/vm_pager.h create mode 100644 usr/src/sys.386bsd/vm/vm_param.h create mode 100644 usr/src/sys.386bsd/vm/vm_prot.h create mode 100644 usr/src/sys.386bsd/vm/vm_statistics.h create mode 100644 usr/src/sys.386bsd/vm/vm_user.c create mode 100644 usr/src/sys.386bsd/vm/vm_user.h create mode 100644 usr/src/sys.386bsd/vm/vnode_pager.c create mode 100644 usr/src/sys.386bsd/vm/vnode_pager.h diff --git a/usr/src/sys.386bsd/conf/defines b/usr/src/sys.386bsd/conf/defines new file mode 100644 index 0000000000..ea7046324e --- /dev/null +++ b/usr/src/sys.386bsd/conf/defines @@ -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 index 0000000000..3ca040a517 --- /dev/null +++ b/usr/src/sys.386bsd/conf/nfsswapvmunix.c @@ -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 index 0000000000..6444f9608d --- /dev/null +++ b/usr/src/sys.386bsd/conf/param.c @@ -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 index 0000000000..0662e28ce8 --- /dev/null +++ b/usr/src/sys.386bsd/i386/Makefile @@ -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 index 0000000000..e1430bcf09 --- /dev/null +++ b/usr/src/sys.386bsd/kern/dead_vnops.c @@ -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 index 0000000000..852b50da71 --- /dev/null +++ b/usr/src/sys.386bsd/kern/fifo_vnops.c @@ -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 index 0000000000..92fdcb77f4 --- /dev/null +++ b/usr/src/sys.386bsd/kern/init_sysent.c @@ -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 index 0000000000..c1e07cf6cf --- /dev/null +++ b/usr/src/sys.386bsd/kern/kern_acct.c @@ -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 index 0000000000..f97eff25fb --- /dev/null +++ b/usr/src/sys.386bsd/kern/kern_kinfo.c @@ -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 index 0000000000..dcde2c163a --- /dev/null +++ b/usr/src/sys.386bsd/kern/kern_ktrace.c @@ -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 index 0000000000..e5291f23fb --- /dev/null +++ b/usr/src/sys.386bsd/kern/kern_time.c @@ -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 index 0000000000..ab93812ed6 --- /dev/null +++ b/usr/src/sys.386bsd/kern/kern_xxx.c @@ -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 index 0000000000..4d8ce97231 --- /dev/null +++ b/usr/src/sys.386bsd/kern/subr_xxx.c @@ -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 index 0000000000..1c2dad23b7 --- /dev/null +++ b/usr/src/sys.386bsd/kern/sys_generic.c @@ -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 index 0000000000..241a12f819 --- /dev/null +++ b/usr/src/sys.386bsd/kern/sys_socket.c @@ -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 index 0000000000..2753835cb0 --- /dev/null +++ b/usr/src/sys.386bsd/kern/syscalls.c @@ -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 index 0000000000..fca74d3f6b --- /dev/null +++ b/usr/src/sys.386bsd/kern/sysv_shm.c @@ -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 index 0000000000..9bfd6cd92f --- /dev/null +++ b/usr/src/sys.386bsd/kern/tty_compat.c @@ -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 index 0000000000..2745f43a53 --- /dev/null +++ b/usr/src/sys.386bsd/kern/tty_conf.c @@ -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 index 0000000000..971dca26ee --- /dev/null +++ b/usr/src/sys.386bsd/kern/tty_tb.c @@ -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 index 0000000000..4a0bed3e27 --- /dev/null +++ b/usr/src/sys.386bsd/kern/tty_tty.c @@ -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 index 0000000000..f8ca170b0c --- /dev/null +++ b/usr/src/sys.386bsd/kern/uipc_domain.c @@ -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 +#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 index 0000000000..fd1dbae02b --- /dev/null +++ b/usr/src/sys.386bsd/kern/uipc_proto.c @@ -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 index 0000000000..38a32b16b3 --- /dev/null +++ b/usr/src/sys.386bsd/kern/uipc_socket.c @@ -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 = ⊤ + 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 = ⊤ + 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 index 0000000000..9c4481d2e3 --- /dev/null +++ b/usr/src/sys.386bsd/kern/uipc_socket2.c @@ -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 index 0000000000..d24de73e63 --- /dev/null +++ b/usr/src/sys.386bsd/kern/vfs_cache.c @@ -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 index 0000000000..9d7668c31e --- /dev/null +++ b/usr/src/sys.386bsd/kern/vfs_lookup.c @@ -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 index 0000000000..98c5a632ab --- /dev/null +++ b/usr/src/sys.386bsd/kern/vfs_subr.c @@ -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 index 0000000000..4684e0924b --- /dev/null +++ b/usr/src/sys.386bsd/net/af.c @@ -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 index 0000000000..3a47cdcc3c --- /dev/null +++ b/usr/src/sys.386bsd/net/af.h @@ -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 index 0000000000..5d7ad064df --- /dev/null +++ b/usr/src/sys.386bsd/net/bpf.h @@ -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 index 0000000000..52a92c794c --- /dev/null +++ b/usr/src/sys.386bsd/net/bpf_filter.c @@ -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 +#include +#include +#include + +#ifdef sun +#include +#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 +#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 index 0000000000..807f1477b7 --- /dev/null +++ b/usr/src/sys.386bsd/net/bpfdesc.h @@ -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 index 0000000000..dc395f5522 --- /dev/null +++ b/usr/src/sys.386bsd/net/if.c @@ -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 index 0000000000..355af2ae40 --- /dev/null +++ b/usr/src/sys.386bsd/net/if_arp.h @@ -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 index 0000000000..65a4109b6f --- /dev/null +++ b/usr/src/sys.386bsd/net/if_dl.h @@ -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 + +__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 index 0000000000..69e8554625 --- /dev/null +++ b/usr/src/sys.386bsd/net/if_ethersubr.c @@ -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 index 0000000000..e9aebdfa15 --- /dev/null +++ b/usr/src/sys.386bsd/net/if_llc.h @@ -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 index 0000000000..5ec4aace48 --- /dev/null +++ b/usr/src/sys.386bsd/net/if_loop.c @@ -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 index 0000000000..076c0518f4 --- /dev/null +++ b/usr/src/sys.386bsd/net/if_slvar.h @@ -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 index 0000000000..70b81957cf --- /dev/null +++ b/usr/src/sys.386bsd/net/if_types.h @@ -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 index 0000000000..534c68c37c --- /dev/null +++ b/usr/src/sys.386bsd/net/netisr.h @@ -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 index 0000000000..5f3df88349 --- /dev/null +++ b/usr/src/sys.386bsd/net/radix.c @@ -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 index 0000000000..349e969540 --- /dev/null +++ b/usr/src/sys.386bsd/net/radix.h @@ -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 index 0000000000..87f6ca4b2a --- /dev/null +++ b/usr/src/sys.386bsd/net/raw_cb.c @@ -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 index 0000000000..aab20b5a24 --- /dev/null +++ b/usr/src/sys.386bsd/net/raw_cb.h @@ -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 index 0000000000..511cff343a --- /dev/null +++ b/usr/src/sys.386bsd/net/raw_usrreq.c @@ -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 index 0000000000..2d69294c55 --- /dev/null +++ b/usr/src/sys.386bsd/net/route.c @@ -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 index 0000000000..4db57cf337 --- /dev/null +++ b/usr/src/sys.386bsd/net/route.h @@ -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 index 0000000000..a64719bf8b --- /dev/null +++ b/usr/src/sys.386bsd/net/rtsock.c @@ -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 index 0000000000..81b354354c --- /dev/null +++ b/usr/src/sys.386bsd/net/slcompress.c @@ -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 +#include +#include +#include +#include +#include + +#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 index 0000000000..f799706fa1 --- /dev/null +++ b/usr/src/sys.386bsd/net/slcompress.h @@ -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 index 0000000000..4e311e4afb --- /dev/null +++ b/usr/src/sys.386bsd/netinet/icmp_var.h @@ -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 index 0000000000..d4e60a5ec7 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/if_ether.c @@ -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 index 0000000000..ef86f7cae9 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/if_ether.h @@ -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 index 0000000000..75824d1a20 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/in.c @@ -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 index 0000000000..be63cbffd1 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/in.h @@ -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 index 0000000000..68c9a54ddc --- /dev/null +++ b/usr/src/sys.386bsd/netinet/in_cksum.c @@ -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 index 0000000000..8b1c06e256 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/in_pcb.c @@ -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 index 0000000000..efbd4e2c9b --- /dev/null +++ b/usr/src/sys.386bsd/netinet/in_pcb.h @@ -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 index 0000000000..c246a599c0 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/in_systm.h @@ -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 index 0000000000..72c48bbb0b --- /dev/null +++ b/usr/src/sys.386bsd/netinet/in_var.h @@ -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 index 0000000000..751dc4d1e0 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/ip.h @@ -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 index 0000000000..69815bde1b --- /dev/null +++ b/usr/src/sys.386bsd/netinet/ip_icmp.c @@ -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 index 0000000000..10bf7fc757 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/ip_icmp.h @@ -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 index 0000000000..889e37004f --- /dev/null +++ b/usr/src/sys.386bsd/netinet/ip_input.c @@ -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 index 0000000000..58dbb05dea --- /dev/null +++ b/usr/src/sys.386bsd/netinet/ip_output.c @@ -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 index 0000000000..f654393b35 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/ip_var.h @@ -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 index 0000000000..d38f340a6c --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp.h @@ -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 index 0000000000..15e0094aca --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_debug.c @@ -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 index 0000000000..4e3372b665 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_debug.h @@ -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 index 0000000000..e9280b5eab --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_fsm.h @@ -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 index 0000000000..f6fcc06b75 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_input.c @@ -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: + * + * 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 index 0000000000..167b193ede --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_output.c @@ -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 index 0000000000..6b90e1ad7a --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_seq.h @@ -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 index 0000000000..b2b1542211 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_subr.c @@ -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 index 0000000000..e372e368d3 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_timer.c @@ -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 index 0000000000..095be439eb --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_timer.h @@ -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: + * + * 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 index 0000000000..317828acc8 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_usrreq.c @@ -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 index 0000000000..0f04c3862a --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcp_var.h @@ -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 index 0000000000..b75a813242 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/tcpip.h @@ -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 index 0000000000..ac6e55d9b7 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/udp.h @@ -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 index 0000000000..778fa635d0 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/udp_usrreq.c @@ -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 index 0000000000..f9e19f8855 --- /dev/null +++ b/usr/src/sys.386bsd/netinet/udp_var.h @@ -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 index 0000000000..2be9d4be60 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs.h @@ -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 index 0000000000..44a48a1aff --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs_bio.c @@ -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 index 0000000000..810378e6ca --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs_node.c @@ -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 index 0000000000..a83dfe9b38 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs_serv.c @@ -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 index 0000000000..ff092d4ccb --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs_socket.c @@ -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 index 0000000000..b274b17fbe --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs_srvcache.c @@ -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 index 0000000000..c6d93c9768 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs_syscalls.c @@ -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 index 0000000000..d08c12dd02 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfs_vfsops.c @@ -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 index 0000000000..fed621ca51 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfscompress.h @@ -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 index 0000000000..bee5d12c13 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfsdiskless.h @@ -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 index 0000000000..0466b7a09d --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfsiom.h @@ -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 index 0000000000..7bbf77c182 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfsm_subs.h @@ -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 index 0000000000..a2a2c5d8c5 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfsmount.h @@ -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 index 0000000000..e08a338cd3 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfsnode.h @@ -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 index 0000000000..7aa6f810f1 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfsrvcache.h @@ -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 index 0000000000..ae46687711 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/nfsv2.h @@ -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 index 0000000000..8f81484afe --- /dev/null +++ b/usr/src/sys.386bsd/nfs/rpcv2.h @@ -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 index 0000000000..5bf212df85 --- /dev/null +++ b/usr/src/sys.386bsd/nfs/xdr_subs.h @@ -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 index 0000000000..6f4067c205 --- /dev/null +++ b/usr/src/sys.386bsd/stand/cat.c @@ -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 index 0000000000..b77d5e25d0 --- /dev/null +++ b/usr/src/sys.386bsd/stand/copy.c @@ -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 index 0000000000..bfe3b05340 --- /dev/null +++ b/usr/src/sys.386bsd/stand/dev.c @@ -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 +#include +#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 index 0000000000..6e18262da6 --- /dev/null +++ b/usr/src/sys.386bsd/stand/ls.c @@ -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 index 0000000000..3a2127ec17 --- /dev/null +++ b/usr/src/sys.386bsd/stand/saerrno.h @@ -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 index 0000000000..6d493045ca --- /dev/null +++ b/usr/src/sys.386bsd/stand/saioctl.h @@ -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 index 0000000000..d75f5f6fa3 --- /dev/null +++ b/usr/src/sys.386bsd/stand/stat.c @@ -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 +#include +#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 index 0000000000..110eca44c1 --- /dev/null +++ b/usr/src/sys.386bsd/sys/acct.h @@ -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 index 0000000000..522be36404 --- /dev/null +++ b/usr/src/sys.386bsd/sys/callout.h @@ -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 index 0000000000..fbe572a444 --- /dev/null +++ b/usr/src/sys.386bsd/sys/cdefs.h @@ -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 index 0000000000..7181093869 --- /dev/null +++ b/usr/src/sys.386bsd/sys/clist.h @@ -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 index 0000000000..ac6034017e --- /dev/null +++ b/usr/src/sys.386bsd/sys/conf.h @@ -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 index 0000000000..bc4ca3ffa9 --- /dev/null +++ b/usr/src/sys.386bsd/sys/dir.h @@ -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 + * and is provided solely (and temporarily) for backward compatibility. + */ + +#ifndef _DIR_H_ +#define _DIR_H_ + +#include + +/* + * 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 index 0000000000..9857d97b92 --- /dev/null +++ b/usr/src/sys.386bsd/sys/dkbad.h @@ -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 index 0000000000..320c65db57 --- /dev/null +++ b/usr/src/sys.386bsd/sys/dkstat.h @@ -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 index 0000000000..5284b410a7 --- /dev/null +++ b/usr/src/sys.386bsd/sys/dmap.h @@ -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 index 0000000000..9555516812 --- /dev/null +++ b/usr/src/sys.386bsd/sys/domain.h @@ -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 index 0000000000..8869d596fa --- /dev/null +++ b/usr/src/sys.386bsd/sys/errno.h @@ -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 index 0000000000..ec539d93fc --- /dev/null +++ b/usr/src/sys.386bsd/sys/exec.h @@ -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 index 0000000000..cc72bca9a1 --- /dev/null +++ b/usr/src/sys.386bsd/sys/fcntl.h @@ -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 ; it also includes + * related kernel definitions. + */ + +#ifndef KERNEL +#include +#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 + +__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 index 0000000000..4ddd510e11 --- /dev/null +++ b/usr/src/sys.386bsd/sys/fifo.h @@ -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 index 0000000000..31f198937e --- /dev/null +++ b/usr/src/sys.386bsd/sys/file.h @@ -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 +#include + +#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 index 0000000000..b6243c28e0 --- /dev/null +++ b/usr/src/sys.386bsd/sys/filedesc.h @@ -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 index 0000000000..03167191a4 --- /dev/null +++ b/usr/src/sys.386bsd/sys/gprof.h @@ -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 index 0000000000..4929a84db7 --- /dev/null +++ b/usr/src/sys.386bsd/sys/ioctl.h @@ -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 + +__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 +#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 index 0000000000..7762049d9e --- /dev/null +++ b/usr/src/sys.386bsd/sys/ioctl_compat.h @@ -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 +#include +#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 index 0000000000..d72a765e69 --- /dev/null +++ b/usr/src/sys.386bsd/sys/ipc.h @@ -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 index 0000000000..fe778edc04 --- /dev/null +++ b/usr/src/sys.386bsd/sys/kernel.h @@ -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 index 0000000000..c4a155c3dd --- /dev/null +++ b/usr/src/sys.386bsd/sys/kinfo.h @@ -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 + +__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 index 0000000000..28b2c177ce --- /dev/null +++ b/usr/src/sys.386bsd/sys/kinfo_proc.h @@ -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 +#include +#include +#include +#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 index 0000000000..9f63359e2d --- /dev/null +++ b/usr/src/sys.386bsd/sys/ktrace.h @@ -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< + +__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 index 0000000000..08e7be464a --- /dev/null +++ b/usr/src/sys.386bsd/sys/malloc.h @@ -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 index 0000000000..654eb32ed2 --- /dev/null +++ b/usr/src/sys.386bsd/sys/mapmem.h @@ -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 index 0000000000..290b917a10 --- /dev/null +++ b/usr/src/sys.386bsd/sys/mbuf.h @@ -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 index 0000000000..b3e19d7a22 --- /dev/null +++ b/usr/src/sys.386bsd/sys/mman.h @@ -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 + +__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 index 0000000000..821b124938 --- /dev/null +++ b/usr/src/sys.386bsd/sys/msgbuf.h @@ -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 index 0000000000..e42c92bd02 --- /dev/null +++ b/usr/src/sys.386bsd/sys/mtio.h @@ -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 index 0000000000..9c8d5ac91b --- /dev/null +++ b/usr/src/sys.386bsd/sys/namei.h @@ -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 index 0000000000..f41c2d0356 --- /dev/null +++ b/usr/src/sys.386bsd/sys/proc.h @@ -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-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 index 0000000000..64222879b6 --- /dev/null +++ b/usr/src/sys.386bsd/sys/protosw.h @@ -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 index 0000000000..e4ca21abb7 --- /dev/null +++ b/usr/src/sys.386bsd/sys/ptrace.h @@ -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 + +__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 index 0000000000..3c33eeafdb --- /dev/null +++ b/usr/src/sys.386bsd/sys/reboot.h @@ -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 index 0000000000..d440d3fb50 --- /dev/null +++ b/usr/src/sys.386bsd/sys/resource.h @@ -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 + +__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 index 0000000000..4374d2d129 --- /dev/null +++ b/usr/src/sys.386bsd/sys/shm.h @@ -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 +#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 index 0000000000..d446d93d28 --- /dev/null +++ b/usr/src/sys.386bsd/sys/signalvar.h @@ -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 index 0000000000..58febae34d --- /dev/null +++ b/usr/src/sys.386bsd/sys/socket.h @@ -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 + +__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 index 0000000000..d8b6ac5339 --- /dev/null +++ b/usr/src/sys.386bsd/sys/socketvar.h @@ -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 index 0000000000..2012ca7ab7 --- /dev/null +++ b/usr/src/sys.386bsd/sys/specdev.h @@ -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 index 0000000000..52948f38e5 --- /dev/null +++ b/usr/src/sys.386bsd/sys/stat.h @@ -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 + +__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 index 0000000000..f4c2c904f2 --- /dev/null +++ b/usr/src/sys.386bsd/sys/syscall.h @@ -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 index 0000000000..6ef56e3d72 --- /dev/null +++ b/usr/src/sys.386bsd/sys/syslimits.h @@ -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 index 0000000000..f5635da03b --- /dev/null +++ b/usr/src/sys.386bsd/sys/syslog.h @@ -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 +#include + +__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 index 0000000000..03340bcb93 --- /dev/null +++ b/usr/src/sys.386bsd/sys/systm.h @@ -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 index 0000000000..e364ce1892 --- /dev/null +++ b/usr/src/sys.386bsd/sys/tablet.h @@ -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 +#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 index 0000000000..649b9cd985 --- /dev/null +++ b/usr/src/sys.386bsd/sys/termios.h @@ -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 + +__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 +#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 index 0000000000..4f12085ae3 --- /dev/null +++ b/usr/src/sys.386bsd/sys/time.h @@ -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 + +#ifndef _POSIX_SOURCE +#include + +__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 index 0000000000..6e048456f0 --- /dev/null +++ b/usr/src/sys.386bsd/sys/timeb.h @@ -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 index 0000000000..52ce6fa55a --- /dev/null +++ b/usr/src/sys.386bsd/sys/times.h @@ -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 + +#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 + +__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 index 0000000000..3bb8daddc9 --- /dev/null +++ b/usr/src/sys.386bsd/sys/tprintf.h @@ -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 index 0000000000..573d3fb70c --- /dev/null +++ b/usr/src/sys.386bsd/sys/trace.h @@ -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 + */ +#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 + */ +#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 */ + +/* + * 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 index 0000000000..27bb20c434 --- /dev/null +++ b/usr/src/sys.386bsd/sys/ttychars.h @@ -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 /* 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 index 0000000000..97a9dffe06 --- /dev/null +++ b/usr/src/sys.386bsd/sys/ttydefaults.h @@ -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 index 0000000000..84b6d38fef --- /dev/null +++ b/usr/src/sys.386bsd/sys/ttydev.h @@ -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 index 0000000000..937219fb48 --- /dev/null +++ b/usr/src/sys.386bsd/sys/types.h @@ -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 +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +#include +#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 index 0000000000..3e99505300 --- /dev/null +++ b/usr/src/sys.386bsd/sys/ucred.h @@ -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 index 0000000000..30d315e6ed --- /dev/null +++ b/usr/src/sys.386bsd/sys/uio.h @@ -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 + +__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 index 0000000000..445878185e --- /dev/null +++ b/usr/src/sys.386bsd/sys/un.h @@ -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 index 0000000000..4d3460af16 --- /dev/null +++ b/usr/src/sys.386bsd/sys/unistd.h @@ -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 index 0000000000..f7014fff61 --- /dev/null +++ b/usr/src/sys.386bsd/sys/unpcb.h @@ -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 index 0000000000..b175752e0a --- /dev/null +++ b/usr/src/sys.386bsd/sys/user.h @@ -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 +#ifndef KERNEL +/* stuff that *used* to be included by user.h, or is now needed */ +#include +#include +#include +#include +#include +#endif +#include +#include +#include /* XXX */ +#include + + +/* + * 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 index 0000000000..71ae7856f0 --- /dev/null +++ b/usr/src/sys.386bsd/sys/vadvise.h @@ -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 index 0000000000..8057499c1d --- /dev/null +++ b/usr/src/sys.386bsd/sys/vcmd.h @@ -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 + +#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 index 0000000000..1306818535 --- /dev/null +++ b/usr/src/sys.386bsd/sys/vlimit.h @@ -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 index 0000000000..99cd4ebc7c --- /dev/null +++ b/usr/src/sys.386bsd/sys/vmmeter.h @@ -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 index 0000000000..42b202b8ce --- /dev/null +++ b/usr/src/sys.386bsd/sys/vnode.h @@ -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 +#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 index 0000000000..e9a78a1c35 --- /dev/null +++ b/usr/src/sys.386bsd/sys/vsio.h @@ -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 index 0000000000..a614568a43 --- /dev/null +++ b/usr/src/sys.386bsd/sys/vtimes.h @@ -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 index 0000000000..de3a50d6f6 --- /dev/null +++ b/usr/src/sys.386bsd/sys/wait.h @@ -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 +#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 +#include + +__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 index 0000000000..599c6a4e27 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/dinode.h @@ -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 index 0000000000..b5c154e5c3 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/dir.h @@ -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 index 0000000000..37ad2b327a --- /dev/null +++ b/usr/src/sys.386bsd/ufs/fs.h @@ -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 index 0000000000..b945ae4238 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/inode.h @@ -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 +#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 index 0000000000..5ac4c6a07a --- /dev/null +++ b/usr/src/sys.386bsd/ufs/lockf.h @@ -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 index 0000000000..d2085f1f08 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/mfs_vfsops.c @@ -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 index 0000000000..855a86bfdc --- /dev/null +++ b/usr/src/sys.386bsd/ufs/mfsiom.h @@ -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 index 0000000000..26735918c8 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/mfsnode.h @@ -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 index 0000000000..a049e62bb7 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/quota.h @@ -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 + +__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 index 0000000000..d40445c5ac --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_alloc.c @@ -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 index 0000000000..cc0a23bf5f --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_bmap.c @@ -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 index 0000000000..34eaa76b1b --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_inode.c @@ -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 index 0000000000..3813d2d90e --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_quota.c @@ -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 index 0000000000..9a730d535f --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_subr.c @@ -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 +#include +#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 index 0000000000..1903e7c2dc --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_tables.c @@ -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 +#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 index 0000000000..785a6c5880 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_vnops.c @@ -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 index 0000000000..262665d25b --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufsmount.h @@ -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 index 0000000000..9130bdbe2d --- /dev/null +++ b/usr/src/sys.386bsd/vm/device_pager.h @@ -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 index 0000000000..4f0eaf7069 --- /dev/null +++ b/usr/src/sys.386bsd/vm/kern_lock.c @@ -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 index 0000000000..fdd00d9f16 --- /dev/null +++ b/usr/src/sys.386bsd/vm/lock.h @@ -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 index 0000000000..0dd019bf01 --- /dev/null +++ b/usr/src/sys.386bsd/vm/pmap.h @@ -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 + +#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 index 0000000000..00175baaab --- /dev/null +++ b/usr/src/sys.386bsd/vm/queue.h @@ -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 index 0000000000..7e9ea7932b --- /dev/null +++ b/usr/src/sys.386bsd/vm/swap_pager.h @@ -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 index 0000000000..2f7d2447c7 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 index 0000000000..c185845ecc --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_inherit.h @@ -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 index 0000000000..e18f64ac20 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_init.c @@ -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 index 0000000000..719c984739 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_map.h @@ -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 index 0000000000..e1dfaa397b --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_meter.c @@ -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 index 0000000000..1c8624fce9 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_object.c @@ -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 index 0000000000..f024f8e519 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_object.h @@ -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 + +/* + * 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 index 0000000000..45aa618722 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_page.h @@ -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 index 0000000000..5270ae322e --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_pageout.c @@ -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 index 0000000000..3f63f758ac --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_pageout.h @@ -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 index 0000000000..c221334c26 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_pager.c @@ -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 index 0000000000..e3e0880645 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_pager.h @@ -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 index 0000000000..8f530d01e7 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_param.h @@ -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 +#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 index 0000000000..dc01b13c34 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_prot.h @@ -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 index 0000000000..82a85c75f0 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_statistics.h @@ -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 index 0000000000..0457a66915 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_user.c @@ -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 index 0000000000..be75db3668 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vm_user.h @@ -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 index 0000000000..635c0fe6fb --- /dev/null +++ b/usr/src/sys.386bsd/vm/vnode_pager.c @@ -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 index 0000000000..cf24d4bda1 --- /dev/null +++ b/usr/src/sys.386bsd/vm/vnode_pager.h @@ -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_ */ -- 2.20.1